Git Product home page Git Product logo

cpp-redis / cpp_redis Goto Github PK

View Code? Open in Web Editor NEW

This project forked from cylix/cpp_redis

704.0 30.0 201.0 2.71 MB

C++11 Lightweight Redis client: async, thread-safe, no dependency, pipelining, multi-platform

License: MIT License

CMake 1.31% Shell 0.23% C++ 76.05% CSS 4.92% JavaScript 4.81% HTML 6.23% TeX 5.49% Starlark 0.96%
cpp cpp11 cpp17 cpp-library redis redis-client unix windows

cpp_redis's Introduction

cpp_redis Build Status Build status

cpp_redis is a C++11 Asynchronous Multi-Platform Lightweight Redis Client, with support for synchronous operations, pipelining, sentinels and high availability.

Requirement

cpp_redis has no dependency. Its only requirement is C++11.

It comes with no network module, so you are free to configure your own, or to use the default one (tacopie)

Example

cpp_redis::client

cpp_redis::client client;

client.connect();

client.set("hello", "42");
client.get("hello", [](cpp_redis::reply& reply) {
  std::cout << reply << std::endl;
});
//! also support std::future
//! std::future<cpp_redis::reply> get_reply = client.get("hello");

client.sync_commit();
//! or client.commit(); for asynchronous call

cpp_redis::client full documentation and detailed example. More about cpp_redis::reply.

cpp_redis::subscriber

cpp_redis::subscriber sub;

sub.connect();

sub.subscribe("some_chan", [](const std::string& chan, const std::string& msg) {
  std::cout << "MESSAGE " << chan << ": " << msg << std::endl;
});
sub.psubscribe("*", [](const std::string& chan, const std::string& msg) {
  std::cout << "PMESSAGE " << chan << ": " << msg << std::endl;
});

sub.commit();

cpp_redis::subscriber full documentation and detailed example.

Wiki

A Wiki is available and provides full documentation for the library as well as installation explanations.

Doxygen

A Doxygen documentation is available and provides full API documentation for the library.

License

cpp_redis is under MIT License.

Contributing

Please refer to CONTRIBUTING.md.

Special Thanks

Mike Moening for his unexpected and incredible great work aiming to port cpp_redis on Windows, provides sentinel support and high availability support!

Author

Simon Ninon

cpp_redis's People

Contributors

10km avatar aardvarkk avatar agasparovic-sabre avatar appkins avatar cmorse avatar cylix avatar dgpetrie avatar edmbernard avatar fpagliughi avatar geoffhadlington avatar holmesconan avatar joybiny avatar knowledge4igor avatar konijnendijk avatar krojew avatar lindblandro avatar lucasterra avatar m-harnish avatar mikesaracade avatar nairis avatar navossoc avatar nerdneilsfield avatar panaali avatar steple avatar theidexisted avatar turanic avatar whoshuu avatar wujunjenny avatar yiurule avatar zodiac403 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cpp_redis's Issues

Create a client pool

#83 Just opened this PR to introduce a client pool. This will allow user code to easily access the functionality from multiple threads, without extra facilities for synchronization.

My question would be:

  • Is this a desired idea?
  • The provided example gives me unexpected results. I thoroughly checked that there are no data races in my code. Is it possible to have multiple threads use different client instances to issue commands?

When reconnecting redis, a callback data can be duplicated.

problem context

0. a client have two database index, so need to re_select()

the problem is here.

  1. when redis sentinel try to reconnect, called connection_disconnection_handler(...)

client::connection_disconnection_handler(network::redis_connection &) {

void
client::reconnect() {
/**
* increase the number of attempts to reconnect
*/
++m_current_reconnect_attempts;
/**
* We rely on the sentinel to tell us which redis server is currently the master.
*/
if (!m_master_name.empty() &&
!m_sentinel.get_master_addr_by_name(m_master_name, m_redis_server, m_redis_port, true)) {
if (m_connect_callback) {
m_connect_callback(m_redis_server, m_redis_port, connect_state::lookup_failed);
}
return;
}
/**
* Try catch block because the redis client throws an error if connection cannot be made.
*/
try {
connect(m_redis_server, m_redis_port, m_connect_callback, m_connect_timeout_ms, m_max_reconnects,
m_reconnect_interval_ms);
}
catch (...) {
}
if (!is_connected()) {
if (m_connect_callback) {
m_connect_callback(m_redis_server, m_redis_port, connect_state::failed);
}
return;
}
/**
* notify end
*/
if (m_connect_callback) {
m_connect_callback(m_redis_server, m_redis_port, connect_state::ok);
}
__CPP_REDIS_LOG(info, "client reconnected ok");
re_auth();
re_select();
resend_failed_commands();
try_commit();
}

  1. That can be successful, so internal m_commands pushed command_request by re_select() and m_buffer builded (by m_client.send(redis_cmd); )

client::unprotected_select(int index, const reply_callback_t &reply_callback) {
/**
* save the index of the database for reconnect attempts.
*/
m_database_index = index;
/**
* save command in the pipeline
*/
unprotected_send({"SELECT", std::to_string(index)}, reply_callback);
}

void
client::unprotected_send(const std::vector<std::string> &redis_cmd, const reply_callback_t &callback) {
m_client.send(redis_cmd);
m_commands.push({redis_cmd, callback});
}

  1. call next function resend_failed_commands()

m_commands is not empty, so ...

void
client::resend_failed_commands() {
if (m_commands.empty()) {
return;
}
/**
* dequeue commands and move them to a local variable
*/
std::queue<command_request> commands = std::move(m_commands);
while (!commands.empty()) {
/**
* Reissue the pending command and its callback.
*/
unprotected_send(commands.front().command, commands.front().callback);
commands.pop();
}
}

m_commands, this variable will still have the previously select(call by unprotected_select()) command

even if commands.pop(), this variable m_commandspushed again (by unprotected_send)

also, m_buffer have duplicate data..

"SELECT" cmd sended twice, so callback data can be weired.. (even if reconnecting successful) ๐Ÿ™€

  1. after try_commit() end of reconnect(), some commands request & response can pushed

but reply is not a current callback, the callback is previous old data when reconnecting (by re_select functions called)

solving problem

I suggest this code:

re_auth(); // => m_commands pushed
resend_failed_commands(); // build buffer from old command and m_commands pushed
re_select(); // build buffer from this new one!
try_commit();

original code:

re_auth();
re_select();
resend_failed_commands();
try_commit();

CMP0048 policy warning if used in a project, that uses this policy.

cpp-redis & tacopie issue

I'm using this library in a project, that uses CMP0048 NEW policy and getting warnings regarding that:

CMake Error (dev) at src/engine/external/cpp_redis/CMakeLists.txt:41 (project):
  Policy CMP0048 is not set: project() command manages VERSION variables.
  Run "cmake --help-policy CMP0048" for policy details.  Use the cmake_policy
  command to set the policy and suppress this warning.

  The following variable(s) would be set to empty:

    PROJECT_VERSION
    PROJECT_VERSION_MAJOR
    PROJECT_VERSION_MINOR
    PROJECT_VERSION_PATCH
    PROJECT_VERSION_TWEAK
This error is for project developers. Use -Wno-error=dev to suppress it.

CMake Error (dev) at src/engine/external/cpp_redis/tacopie/CMakeLists.txt:41 (project):
  Policy CMP0048 is not set: project() command manages VERSION variables.
  Run "cmake --help-policy CMP0048" for policy details.  Use the cmake_policy
  command to set the policy and suppress this warning.

  The following variable(s) would be set to empty:

    PROJECT_VERSION
    PROJECT_VERSION_MAJOR
    PROJECT_VERSION_MINOR
    PROJECT_VERSION_PATCH
    PROJECT_VERSION_TWEAK
This error is for project developers. Use -Wno-error=dev to suppress it.

I'm building my project with AppVeyor and it's explicitly handling warnings as errors and turning that off seems to be a bad option security-wise.

A litte bit of googling told me that this might help?
Tencent/rapidjson#1154 (comment)

if (POLICY CMP0048)
  cmake_policy(SET CMP0048 OLD)
endif()

Edit:
SRombauts/SQLiteCpp#184 (comment)

It seems to be a bad idea to use POLICY OLD, as it will be deprecated in the future.
Setting a proper version number seems to be the correct way to solve this.

Issue detected using sentinel

Hi I had problems to use de last master version, in HA mode.
Never conneted to sentinels
I have found the problem in sentinels.cpp

Here your code , the command is wrong "get-master-addr-by-m_name" should be
"get-master-addr-by-name"

send({"SENTINEL", "get-master-addr-by-m_name", name}, [&](cpp_redis::reply& reply) {
if (reply.is_array()) {
auto arr = reply.as_array();
host = arr[0].as_string();
port = std::stoi(arr[1].as_string(), nullptr, 10);
}
});
sync_commit();

I hope that this helps you
God job!
Best regards,
Roni

Consider std::move-ing callbacks into the command list instead of const references

Because the callbacks are passed in as const references, the final step where the callback is inserted into the command queue results in a copy. This is expensive if the callback is a functor object with a lot of state.

m_commands.push({redis_cmd, callback});

If the callbacks were instead passed by value, and forwarded into the command queue via std::move, C++17 copy elision would eliminate the copies.

m_commands.emplace(redis_cmd, std::move(callback));

This sort of thing is typical with asio callbacks and could be applied here as well.

sentinel reconnect problem, and the high availability example failed

Using the example of cpp_redis_high_availability_client
Here is my docker-compose file and redis.conf:
docker-compose file:

version: '2'

services:
  redis-master:
    image: redis:latest
    volumes:
        - ./redis-master.conf:/etc/redis/redis.conf
    command: redis-server /etc/redis/redis.conf
    ports:
        - "8000:8000"

  redis-slave1:
     image: redis:latest
     volumes:
        - ./redis-slave1.conf:/etc/redis/redis.conf
     command: redis-server /etc/redis/redis.conf
     ports:
        - "8001:8001"

  redis-slave2:
     image: redis:latest
     volumes:
        - ./redis-slave2.conf:/etc/redis/redis.conf
     command: redis-server /etc/redis/redis.conf
     ports:
        - "8002:8002"

  redis-sentinel:
     image: redis:latest
     volumes:
        - ./redis-sentinel.conf:/etc/redis/redis.conf
     command: redis-sentinel /etc/redis/redis.conf
     ports:
        - "28000:28000"

redis-sentinel.conf:

port 28000

sentinel monitor test-master 10.88.231.131 8000 1

sentinel down-after-milliseconds test-master 30000

sentinel parallel-syncs test-master 1

sentinel failover-timeout test-master 180000

redis-master.conf:
port 8000
redis-slave1.conf:


port 8001

slaveof 10.88.231.131 8000

slave-priority 100

slave-read-only yes

redis-slave2.conf

port 8002

slaveof 10.88.231.131 8000

slave-priority 10

slave-read-only yes

In the code, If I disable cpp_redis::network::set_default_nb_workers(2);, it will work then I stop the master, it won't try to reconnect the sentinel's new master and the programmer blocked and do nothing.
if the cpp_redis::network::set_default_nb_workers(2); enabled, it will do nothing but block on the connect function

//! Enable logging
	cpp_redis::active_logger = std::unique_ptr<cpp_redis::logger>(new cpp_redis::logger);

	// disable this, it will work but won't reconnect after the master is down. 
	// cpp_redis::network::set_default_nb_workers(2);

	cpp_redis::client client;

	//! Add your sentinels by IP/Host & Port
	client.add_sentinel("10.88.231.131", 28000);
       
       // block on here.
	client.connect("test-master", [](const std::string& host, std::size_t port, cpp_redis::client::connect_state status) {
		if (status == cpp_redis::client::connect_state::dropped) {
			std::cout << "client disconnected from " << host << ":" << port << std::endl;
		}
	},
		0, -1, 5000);


cpp-redis is quite great and I think will replace the hiredis sooner or later, please take a look at this issue.
the code is running on win with VS2015 and I installed the cpp-redis with vcpkg.
please take a look at this issue, thanks a lot

Why established too many connections with server?

Hi, I have encountered a critical issue, when I run the client and connect to redis server, it's seems the cpp_redis created around 30K connections , I have turned on the logs of cpp_redis and tacopie, the log seems no problem - please see attached the log files.

In the app_logs.txt we can see the cpp_reis and tacopie logs.
In the app_lsof.log we can see the TCP connections which established from my app to redis server.
I've added some logs in tacopie for log the create_socket_if_necessary() functions.

In the redis-server.log we can see the redis server log shows it accepted the connections.

The application run on CentOS 7.5, X64, and redis server is 4.0.11.

Please help, don't know why cause this problem, thanks in advance.

app_logs.txt
app_lsof.log
redis-server.log

xmessage non-virt dtor compile warning.

Describe the bug
Ok, so not a bug per se, but wondering if this is expected and if so, why not dealt with?

Ubuntu 18.04, clang 7, llvm. Generic make of cpp_redis yields...

warning: destructor called on non-final 'cpp_redis::xmessage' that has virtual functions but non-virtual destructor [-Wdelete-non-virtual-dtor]

To Reproduce
Ubuntu 18.04, pull repo, set env CC CXX to clang, add libc++ into CMakeFile.txt, build per instructions, see Warning.

Expected behavior
Error-free build.

Screenshots
xmessage-warning

Desktop (please complete the following information):

  • OS: Linux
  • Version: Ubuntu 18.04

I added a virtual dtor in xmessage decl

        class xmessage : public message_type {
	public:
			xmessage();
			virtual ~xmessage() {};

			explicit xmessage(const reply_t &data);

			friend std::ostream &operator<<(std::ostream &os, const xmessage &xm);
	};

and the warning is gone as expected.

Just wondering if this is a known issue and if it was left as-is on purpose?

Thanks.

SSL Support

Is your feature request related to a problem? Please describe.

We can't connect to cloud based Redis servers. For production, they require SSL as the Auth token would otherwise be sent in the clear.

Describe the solution you'd like

SSL support. I gather this would be the underlying networking library - if so, has anyone done SSL?

Describe alternatives you've considered

There really aren't any :(

As Tacopie isn't maintained, I checked around. There have been a few forks, but none of them seem to be substantially different. I have a bad feeling hacking in SSL support would be a little bit of work. Maybe that's not cpp_redis's issue, but without it (or support) cpp_redis is useless to us :(

Great thing to find out just before we're going production .... Doh!

Additional context

Thread deadlock caused by a large number of asynchronous requests

OS : Windows
Visual Studio : VS 2019 -> C++17 compiler
version : cpprestsdk 2.10 -> 2019 Release

In our project, we are using CppRestSDK to make requests to the API server.
However, I have seen thread deadlocks for a large number of API requests.
In order to perform a completely asynchronous operation, we made the API request and then receive an operation through .then(), and we do not use the .wait() function.

image

/// -----
ex)

for () // -> count loop test
{

http_client client(U("url"));
client.request(U("GET")).then([](http_response resp){
  wcout << U("STATUS : ") << resp.status_code() << endl;
  wcout << "content-type : " << resp.headers().content_type() << endl;
  
  resp.extract_string(true).then([](string_t sBoby){
      wcout << sBoby << endl;
  });
})

}

/// -----

We have repeatedly requested a large number of API requests in the way we tested, and if approximately 1000 or more requests are executed within one code block,
You have noticed that the asynchronous thread enters an infinite lock state.

Please let me know if you have a suitable solution for this, or if you have any guidelines for API calls.

Here's what we think about.

  1. Execute .wait() until the thread receives the result at the same time as the request. (The thread that executes the request is managed asynchronously.)
  2. Request by controlling the number of requests that can be called at one time.

thread_pool::fetch_task_or_stop causes the program to pause

code:

try
{
	cpp_redis::client client;
	client.connect(ip, 6379, [&](const std::string& host, std::size_t port, cpp_redis::connect_state status) {});
	client.sync_commit();
	client.hgetall(key, [](const cpp_redis::reply& reply){
		throw std::runtime_error("what happend!");
	});
	client.sync_commit();
}
catch(const std::exception& e)
{
	std::cerr << e.what() << '\n';
}

when I throw an exception in the labmda expression of hgetall, it goes to line 70 (in the file thread_pool.cpp).
Continue debugging, programm will pause when excute to line 124 (in the file thread_pool.cpp).

So, how can i get the exception out of the lambda expression?

platform: Windows10, VS2019-16.7.5

Thank you!

Exception thrown in tacopie when publishing

Hi there,

I really like the platform and thank you for continuing to maintain a great project.

I have a query though regarding Publishing as it may be broken in the latest build. Although I can subscribe to a channel fine no messages are actually received.. But I noticed that the debug window was showing an exception thrown by tacopie and a memory address. I can't locate the problem however.

I am running two separate processes - one for pub the other for sub.

I am using Redis 4.0.

Any suggestions please?

Thanks

CONTRIBUTING.md testing instructions

In CONTRIBUTING.md:
4. Build the entire library:
It referes to tests:
./bin/subscriber
./bin/client

Pardon, my ignorance if I missed something as I am a bit of a cmake newbie. I am not seeing any rules to build these targets.

Subscribe-send nest

I created a subscriber that when triggered executes a callback that inside performs a send request
The send request stuck into an infinite wait.
Any suggestion?

sub.psubscribe("Configurations.Requests.*", [this](const std::string& chan, const std::string& msg) {
   client.send({ "JSON.GET", "config" }, [this](cpp_redis::reply& reply) {
      _logger->info("{}", reply.as_string());
   });
}).commit();

sentinel::slaves not showing slave info?

I setup a master with two slaves and using three sentinels. I can connect using sentinel without any issue. However, when I'm querying slave status as below:
client.get_sentinel().slaves(, [](const reply& reply) { std::cout << reply << std::endl; }).sync_commit(1s);
I always get "connect error: tcp_client is disconnected" exception. Is this known issue or I am doing something wrong?

"cpp_redis::client" has no member "connect_state"

When I try to build a VS console app with cpp_redis, the build fails with the error "cpp_redis::client" has no member "connect_state". I actually started with cpp_redis in an Unreal Engine 4 application where I first saw the issue. I figured it could be related to something in UE4 so tested it out in a console application where I get the same error.

VS 2017
v1.41 Build tools with 10.xx SDK
x64 and Release configuration

Both cpp_redis and tacopie build successfully with no warnings.

The following snippet from the console application builds successfully so I'm pretty sure that I'm linking the two libs properly.

cpp_redis::client client;
client.connect();

When I try to connect with the following I get the build error referenced above.

client.connect("192.168.0.179", 6379, [](const std::string& host, std::size_t port, cpp_redis::client::connect_state status) {
	if (status == cpp_redis::client::connect_state::dropped) {
		std::cout << "client disconnected from " << host << ":" << port << std::endl;
	}
}); 

I get the same error when I try to connect a subscriber. I can't find any reference to anybody else having this problem so it's got to be something specific to me, especially since I see it in two different applications, but I just don't know what. Any ideas what I'm doing wrong?

error while compile

Describe the bug
I try to test code in the example markdown as :

#include <cpp_redis/cpp_redis>

#include <iostream>

#ifdef _WIN32
#include <Winsock2.h>
#endif /* _WIN32 */

int
main(void) {
#ifdef _WIN32
  //! Windows netword DLL init
  WORD version = MAKEWORD(2, 2);
  WSADATA data;

  if (WSAStartup(version, &data) != 0) {
    std::cerr << "WSAStartup() failure" << std::endl;
    return -1;
  }
#endif /* _WIN32 */

  //! Enable logging
  cpp_redis::active_logger = std::unique_ptr<cpp_redis::logger>(new cpp_redis::logger);

  cpp_redis::client client;

  client.connect("127.0.0.1", 6379, [](const std::string& host, std::size_t port, cpp_redis::client::connect_state status) {
    if (status == cpp_redis::client::connect_state::dropped) {
      std::cout << "client disconnected from " << host << ":" << port << std::endl;
    }
  });

  // same as client.send({ "SET", "hello", "42" }, ...)
  client.set("hello", "42", [](cpp_redis::reply& reply) {
    std::cout << "set hello 42: " << reply << std::endl;
    // if (reply.is_string())
    //   do_something_with_string(reply.as_string())
  });

  // same as client.send({ "DECRBY", "hello", 12 }, ...)
  client.decrby("hello", 12, [](cpp_redis::reply& reply) {
    std::cout << "decrby hello 12: " << reply << std::endl;
    // if (reply.is_integer())
    //   do_something_with_integer(reply.as_integer())
  });

  // same as client.send({ "GET", "hello" }, ...)
  client.get("hello", [](cpp_redis::reply& reply) {
    std::cout << "get hello: " << reply << std::endl;
    // if (reply.is_string())
    //   do_something_with_string(reply.as_string())
  });

  // commands are pipelined and only sent when client.commit() is called
  // client.commit();

  // synchronous commit, no timeout
  client.sync_commit();

// synchronous commit, timeout
// client.sync_commit(std::chrono::milliseconds(100));

#ifdef _WIN32
  WSACleanup();
#endif /* _WIN32 */

  return 0;
}

I follow the command line in
https://github.com/cpp-redis/cpp_redis/wiki/Mac-&-Linux-Install
to install cpp_redis

and use

gcc -lstdc++ -lcpp_redis -ltacopie --std=c++11 test_redis.cpp -o testredis

to compile the code.

But it come out a error ๏ผš

bash-5.0# gcc -lstdc++ -lcpp_redis -ltacopie --std=c++11 test_redis.cpp -o testredis
test_redis.cpp: In function 'int main()':
test_redis.cpp:27:104: error: 'cpp_redis::client::connect_state' has not been declared
   27 |     client.connect("127.0.0.1", 6379, [](const std::string& host, std::size_t port, cpp_redis::client::connect_state status) {
      |                                                                                                        ^~~~~~~~~~~~~
test_redis.cpp: In lambda function:
test_redis.cpp:28:46: error: 'cpp_redis::client::connect_state' has not been declared
   28 |             if (status == cpp_redis::client::connect_state::dropped) {
      |                                              ^~~~~~~~~~~~~
test_redis.cpp: In function 'int main()':
test_redis.cpp:31:14: error: no matching function for call to 'cpp_redis::client::connect(const char [10], int, main()::<lambda(const string&, std::size_t, int)>)'
   31 |             });
      |              ^
In file included from /usr/local/include/cpp_redis/cpp_redis:30,
                 from test_redis.cpp:1:
/usr/local/include/cpp_redis/core/client.hpp:116:9: note: candidate: 'void cpp_redis::client::connect(const string&, std::size_t, const connect_callback_t&, uint32_t, int32_t, uint32_t)'
  116 |    void connect(
      |         ^~~~~~~
/usr/local/include/cpp_redis/core/client.hpp:119:32: note:   no known conversion for argument 3 from 'main()::<lambda(const string&, std::size_t, int)>' to 'const connect_callback_t&' {aka 'const std::function<void(const std::__cxx11::basic_string<char>&, long unsigned int, cpp_redis::connect_state)>&'}
  119 |      const connect_callback_t &connect_callback = nullptr,
      |      ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/cpp_redis/core/client.hpp:134:9: note: candidate: 'void cpp_redis::client::connect(const string&, const connect_callback_t&, uint32_t, int32_t, uint32_t)'
  134 |    void connect(
      |         ^~~~~~~
/usr/local/include/cpp_redis/core/client.hpp:136:32: note:   no known conversion for argument 2 from 'int' to 'const connect_callback_t&' {aka 'const std::function<void(const std::__cxx11::basic_string<char>&, long unsigned int, cpp_redis::connect_state)>&'}
  136 |      const connect_callback_t &connect_callback = nullptr,
      |      ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~

To Reproduce
Steps to reproduce the behavior:

  1. follow https://github.com/cpp-redis/cpp_redis/wiki/Mac-&-Linux-Install to install cpp_redis
  2. copy code in https://github.com/cpp-redis/cpp_redis/wiki/Examples#redis-client to a file(test_redis.cpp)
  3. try gcc -lstdc++ -lcpp_redis -ltacopie --std=c++11 test_redis.cpp -o testredis to compile

Expected behavior
compile success with no error or warning.

Screenshots
all codes, steps and outputs have been shown above.

Desktop (please complete the following information):

  • firecracker microVM
  • uname -a : Linux dab7670245ef 4.15.0-91-generic #92-Ubuntu SMP Fri Feb 28 11:09:48 UTC 2020 x86_64 Linux
  • alpine

Cannot Use cpp_redis with CMake and VCPKG

Describe the bug
Trying to create a Docker image for a C++ application using cpp-redis installed with VCPKG and built with CMake 13.4.5:

[100%] Linking CXX executable micro-service
/usr/bin/ld: cannot find -lcpp_redis
/usr/bin/ld: cannot find -ltacopie
collect2: error: ld returned 1 exit status
make[2]: *** [micro-service] Error 1

This doesn't happen on my Ubuntu 1804.

A temporary solution would be providing full path for the files like this:

        ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib/libcpp_redis.a
        ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib/libtacopie.a

For some reason I need that only in the case of cpp-redis and tacopie.

I tried using pkg-config which could find the library but I still had the same errors only in Docker:

find_package(PkgConfig REQUIRED)
pkg_check_modules(cpp_redis REQUIRED cpp_redis)

Making verbose build generates the same building command both in my Ubuntu and inside Docker. However, I get the error only in Docker:
/usr/bin/c++ -O3 -DNDEBUG CMakeFiles/micro-service.dir/main.cpp.o CMakeFiles/micro-service.dir/microsvc_controller.cpp.o CMakeFiles/micro-service.dir/foundation/basic_controller.cpp.o CMakeFiles/micro-service.dir/cache/redis_cache.cpp.o -o micro-service /usr/lib64/libsoci_sqlite3.so.4.0.0 /tmp/vcpkg/installed/x64-linux/lib/libfmt.a -lcpp_redis -ltacopie /tmp/vcpkg/installed/x64-linux/lib/libhttp_parser.a /usr/lib64/libsoci_core.so.4.0.0 -lpthread /usr/lib/x86_64-linux-gnu/libdl.so /tmp/vcpkg/installed/x64-linux/lib/libsqlite3.a

To Reproduce
Steps to reproduce the behavior:

  1. Download this project https://github.com/ahmedyarub/micro-service
  2. Do docker build .

Expected behavior
A Docker image is created without errors

Desktop (please complete the following information):

  • OS: Ubuntu 18.04
  • Version: 4.3.1-1

Redis client xrevrange command has an issue with reading n elements from given stream

As per xrevrange documentation, to get number of elements from given stream "COUNT" word needs to be there before actual value which is missing in current code.

Current code:

	client &
	client::xrevrange(const std::string &key, const range_options_t &range_args, const reply_callback_t &reply_callback) {
		std::vector<std::string> cmd = {"XREVRANGE", key, range_args.Start, range_args.Stop};
		if (range_args.Count > 0) {
			cmd.emplace_back(std::to_string(range_args.Count));
		}
		send(cmd, reply_callback);
		return *this;
	}

Fixed code:

	client &
	client::xrevrange(const std::string &key, const range_options_t &range_args, const reply_callback_t &reply_callback) {
		std::vector<std::string> cmd = {"XREVRANGE", key, range_args.Start, range_args.Stop};
		if (range_args.Count > 0) {
			cmd.emplace_back("COUNT");
			cmd.push_back(std::to_string(range_args.Count));
		}
		send(cmd, reply_callback);
		return *this;
	}

How to find out sync timed out or a success return

After I call redis_client->sync_commit(std::chrono::milliseconds(2000), how can I check if the return is a success or is timeout. I tried research on net, could not find the info.

Also if it is time out, how can I flush or clear callbacks so the logic is not processed late.

I am seeing timeout in the logic, as my data is not set from the reply, the processes continues.
But little later the "reply" comes and while setting the data I get a core.

At a high level search my issue looked closer to
"cpp_redis::client causes program to crash Cylix#156"

Binary data broken?

Is your feature request related to a problem? Please describe.
I can't store binary data in Redis via cpp_redis, although I can with other languages

Describe the solution you'd like
Is there a way to call "set" with something other than a std::string / i.e. a raw buffer and size?

Describe alternatives you've considered
I'm temporarily (for about 40 seconds) storing some PNG files into Redis. Unfortunately, the .set command uses std::string. Normally I would applaud this, but in this case it's causing a double allocation and a corrupt file.

ALL of the std::string initializers either walk the string and set every character to zero, or do a deep copy and null terimate the copy. They also null terminate the string. A binary file, which IS compatible with Redis, doesn't have to be null terminated. If I copy a PNG file with a null at the end, it may cause the file to be corrupt.

I'm dealing with a few hundred K, with the largest about a meg and a half, so creating a C++ string by allocating bytes that will subsequently be immedietely overwritten by OpenGL buffer copies seems wasteful.

So essentially, cpp_redis cannot store data that Redis is capable of storing? Or is there a way around this?

I looked at std::string_view but I can't quite coerce that into std:string. I'm using QT library, which does have a way to initialize a raw buffer to a QString, but I found out that .toStdString will also do a deep copy to put the null terminated string.

Regarding other languages, for example, with php/Predis:

$client = new Predis\Client();
$client->set('profile_picture', file_get_contents("profile.png"));//value is binary

Additional context

I'm using OpenGL to create some small thumbnails for a graphical editor. Right now, it can take up to 30 seconds at hosting to open a webcache and dump the data there, and we're using the premium service. It's mostly as there are dozens of small files, and each "file/open" takes a long time. We were attempting to create a Redis Cashe for this data until the data is persisted to disk. We are would lose clients dramatically if every change took 30 seconds until it was visible.

Redis_Client is_connected=true, even when network redis device is unplugged

Describe the bug
I connect to a remote redis-server. Later if i disconnect the remote device from network, redis_client still says is_connected=true

OS: ubuntu18,04
Aarch 64
cpp_redis: 4.4.0-beta.1 and master

int main() {

    cpp_redis::client redis_client;
    auto connCallbackFn = [&redis_client](const std::string& host,
                                          std::size_t port,
                                          cpp_redis::connect_state status) {
        std::string name = "Redis";
        LOG(ERROR) << "Redis Connector callback made. Status: ";
        if (status == cpp_redis::connect_state::dropped)
            LOG(INFO) << name << " Connection: Dropped";
        else if (status == cpp_redis::connect_state::start)
            LOG(INFO) << name << " Connection: Start";
        else if (status == cpp_redis::connect_state::sleeping)
            LOG(INFO) << name << " Connection: Sleeping";
        else if (status == cpp_redis::connect_state::ok)
            LOG(INFO) << name << " Connection: OK";
        else if (status == cpp_redis::connect_state::failed)
            LOG(INFO) << name << " Connection: Failed";
        else if (status == cpp_redis::connect_state::lookup_failed)
            LOG(INFO) << name << " Connection: LookupFailed";
        else if (status == cpp_redis::connect_state::stopped)
            LOG(INFO) << name << " Connection: Stopped";
    };
    redis_client.connect("192.168.0.17", 6379, connCallbackFn, 2000);
    while (true) {
        if (redis_client.is_connected())
            LOG(INFO) << "Connected...";
        else
            LOG(INFO) << "Not connected...";
        std::this_thread::sleep_for(std::chrono::seconds(2));
    }
}

Logs:

E0525 21:09:37.313364  2975 test_redis.cpp:14] Redis Connector callback made. Status: 
I0525 21:09:37.313477  2975 test_redis.cpp:18] Redis Connection: Start
E0525 21:09:37.314191  2975 test_redis.cpp:14] Redis Connector callback made. Status: 
I0525 21:09:37.314225  2975 test_redis.cpp:22] Redis Connection: OK
I0525 21:09:37.314242  2975 test_redis.cpp:33] Connected...
I0525 21:09:39.314694  2975 test_redis.cpp:33] Connected...

<UNPLUG REMOTE DEVICE FROM NETWORK>

I0525 21:09:41.315685  2975 test_redis.cpp:33] Connected...

Once i unplug my remote device with redis-server from network, I expect another callback, and the redis_client.is_connected() should return false.

Am I understanding it wrong. How to get informed if redis_client connection is lost?

Update Custom Network Module in Wiki

I'm writing a network module using the Qt framework instead of Taco Pie, and I have come across several parts of the Wiki that are missing or require clarification.

  1. For the function async_read, the size member of a read_request struct appears to be the requested size of the read buffer rather than the number of bytes that are expected. It is the value of __CPP_REDIS_READ_SIZE as defined in network/redis_connection.hpp.

  2. The function set_on_disconnect_handler is not mentioned, and the documentation in network/tcp_client_iface.hpp isn't very specific. Is the function supposed to be called when any disconnect occurs, or only one that occurs because of an error?

    /**
    * disconnection handler
    *
    */
    typedef std::function<void()> disconnection_handler_t;
    /**
    * set on disconnection handler
    *
    * @param disconnection_handler handler to be called in case of a disconnection
    *
    */
    virtual void set_on_disconnection_handler(const disconnection_handler_t& disconnection_handler) = 0;

  3. The sidebar links to the archive repository instead of this one. Any change in the Wiki for this repository could easily be missed.

cpp_redis_streams_client.cpp hangs

Describe the bug
A clear and concise description of what the bug is.
cpp_redis_streams_client hangs

To Reproduce

Steps to reproduce the behavior:

  1. git clone https://github.com/cpp-redis/cpp_redis.git
  2. cd cpp_redis
  3. git submodule init && git submodule update
  4. mkdir build && cd build
  5. CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake .. -DCMAKE_BUILD_TYPE=Release
  6. make
  7. make install
  8. vi examples/CMakeLists.txt, change line to target_link_libraries(${EXAMPLE} cpp_redis tacopie)
  9. cd examples
  10. mkdir build
  11. cd build
  12. CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake ..
  13. ./cpp_redis_streams_client

Expected behavior
Some std::cout output, the program seems to hang before that line.

Is this feature already implemented in cpp_redis?

cluster support?

hi there.

Do you have a cluster support plan?

I would like to know if there is a client cluster support for cpp_redis, or do you have the plan for this feature, because cluster support is very important to plan server application.

Wrong return value after disconnect while using AUTH

Describe the bug
The return value of the first command that happens after a reconnect to a server that uses AUTH is just the string "OK" instead of the expected reply.

To Reproduce
Steps to reproduce the behavior:

  1. start a local service with authentication enabled (requirepass foobared in redis.conf)
  2. open a connection with the client, send the "AUTH foobared" command
  3. use the client to send the command "SET somekey 1"
  4. restart the service, the client reconnects
  5. use the client to send the command "INCR somekey"
  6. the command returns "OK"

Expected behavior
the last command should return 2

Desktop (please complete the following information):

  • OS: ubuntu

Redis5 support?

Can I use this library with Redis 5? Six months ago someone asked when Redis 5 support is coming and received no answer (#50). Can somebody please comment on the state of using Redis 5 so I know whether I should keep looking for another library?

CMake custom TCP clienet throws make errors

Describe the bug
Currently am trying to compile the library via CMake. CMake is able to generate the files but as soon as I try to build the library it throws errors. The errors only show if I compile using TCP Custom module. If I do not use it then I can compile the library.

To Reproduce

cmake .. -DCMAKE_BUILD_TYPE=Release -DUSE_CUSTOM_TCP_CLIENT=1
make

Additional context

Scanning dependencies of target cpp_redis
[  5%] Building CXX object CMakeFiles/cpp_redis.dir/sources/builders/array_builder.cpp.o
[ 11%] Building CXX object CMakeFiles/cpp_redis.dir/sources/builders/builders_factory.cpp.o
[ 17%] Building CXX object CMakeFiles/cpp_redis.dir/sources/builders/bulk_string_builder.cpp.o
[ 23%] Building CXX object CMakeFiles/cpp_redis.dir/sources/builders/error_builder.cpp.o
[ 29%] Building CXX object CMakeFiles/cpp_redis.dir/sources/builders/integer_builder.cpp.o
[ 35%] Building CXX object CMakeFiles/cpp_redis.dir/sources/builders/reply_builder.cpp.o
[ 41%] Building CXX object CMakeFiles/cpp_redis.dir/sources/builders/simple_string_builder.cpp.o
[ 47%] Building CXX object CMakeFiles/cpp_redis.dir/sources/core/client.cpp.o
[ 52%] Building CXX object CMakeFiles/cpp_redis.dir/sources/core/consumer.cpp.o
/home/dev/libs/cpp_redis/sources/core/consumer.cpp: In constructor โ€˜cpp_redis::consumer_client_container::consumer_client_container()โ€™:
/home/dev/libs/cpp_redis/sources/core/consumer.cpp:32:85: error: no matching function for call to โ€˜cpp_redis::client::client()โ€™
  consumer_client_container::consumer_client_container() : ack_client(), poll_client() {
                                                                                     ^
In file included from /home/dev/libs/cpp_redis/includes/cpp_redis/core/consumer.hpp:27:0,
                 from /home/dev/libs/cpp_redis/sources/core/consumer.cpp:23:
/home/dev/libs/cpp_redis/includes/cpp_redis/core/client.hpp:83:13: note: candidate: cpp_redis::client::client(const std::shared_ptr<cpp_redis::network::tcp_client_iface>&)
    explicit client(const std::shared_ptr<network::tcp_client_iface> &tcp_client);
             ^~~~~~
/home/dev/libs/cpp_redis/includes/cpp_redis/core/client.hpp:83:13: note:   candidate expects 1 argument, 0 provided
/home/dev/libs/cpp_redis/sources/core/consumer.cpp:32:85: error: no matching function for call to โ€˜cpp_redis::client::client()โ€™
  consumer_client_container::consumer_client_container() : ack_client(), poll_client() {
                                                                                     ^
In file included from /home/dev/libs/cpp_redis/includes/cpp_redis/core/consumer.hpp:27:0,
                 from /home/dev/libs/cpp_redis/sources/core/consumer.cpp:23:
/home/dev/libs/cpp_redis/includes/cpp_redis/core/client.hpp:83:13: note: candidate: cpp_redis::client::client(const std::shared_ptr<cpp_redis::network::tcp_client_iface>&)
    explicit client(const std::shared_ptr<network::tcp_client_iface> &tcp_client);
             ^~~~~~
/home/dev/libs/cpp_redis/includes/cpp_redis/core/client.hpp:83:13: note:   candidate expects 1 argument, 0 provided
CMakeFiles/cpp_redis.dir/build.make:254: recipe for target 'CMakeFiles/cpp_redis.dir/sources/core/consumer.cpp.o' failed
make[2]: *** [CMakeFiles/cpp_redis.dir/sources/core/consumer.cpp.o] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/cpp_redis.dir/all' failed
make[1]: *** [CMakeFiles/cpp_redis.dir/all] Error 2
Makefile:129: recipe for target 'all' failed
make: *** [all] Error 2```

Nested Array Data Output Formating & Extraction

Hello,

I am trying to format output data within the fields portion of the XADD command. With the following commands:

const std::string session_name = "Data";

	client.xadd(session_name, "*", {{"Harry", "54"}, {"Jane", "41"}, {"Laura", "25"}, 
									{"Nicky", "36"}, {"Kevin", "32"}}, 
											[](cpp_redis::reply &reply) {

	});

	client.xrange(session_name, {"-", "+", 10}, [](cpp_redis::reply &reply){

		if(reply.is_array()) {
				for(const auto key : reply.as_array()) {
	 			     std::cout << key << std::endl;
		}
	});

client.sync_commit();

This is the current output:

1594282837961-0Harry54Jane41Kevin32Laura25Nicky36

I want to pass this information to another application but in a format that looks like this:

1594282837961-0 Harry 54 Jane 41 Kevin 32 Laura 25 Nicky 36

I have been trying multi dimensional vector manipulations to the code as I understand that this part of the output is a nested array within the default array response from redis. Nothing is working at the moment.

Can anyone help with this please?
Thanks.

Application cores with SIGSEGV, Segmentation fault. memcpy_sse2_unaligned

Describe the bug
After timeout is returned to the application for SYNC_COMMIT(2 sec) for HMGET command, the library callsback HMGET when the delayed response comes.
This causes the application to core with SIGSEGV memcpy_sse2_unaligned.

To Reproduce
Application code portion for this logic.
The core line indicates the core @ pCollabMediaUUID->assign(reply.as_array()[0].as_string());

m_redis_client->hmget(sipuricallidhashKey, hmGetFields, [this, &sipuricallidhashKey, &pCollabMediaUUID,
                                                               &pIdentity, &pDeviceId]
                                                               (cpp_redis::reply& reply) {
    LOG_INFO << m_callId << " : "
             << "hmget for sipuricallidhashKey : " << sipuricallidhashKey;
    if (reply.is_array() && reply.as_array().size() == 3 &&
        reply.as_array()[0].is_string() &&
        reply.as_array()[1].is_string() && reply.as_array()[2].is_string()) {
        pCollabMediaUUID->assign(reply.as_array()[0].as_string());
        pIdentity->assign(reply.as_array()[1].as_string());
        pDeviceId->assign(reply.as_array()[2].as_string());
    } else {
        LOG_ERROR << m_callId << " : "
                  << "getClientDetails - FAILED to Read from redis";
    }
});

// synchronous commit, timeout
m_redis_client->sync_commit(std::chrono::milliseconds(REDIS_TIMEOUT));

Expected behavior
Expected behavior is not to get the callback for HMGET after the timeout handling is processed.

Screenshots
gdb output of the core file:
(gdb) bt
#0 __memcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:37
#1 0x00007f7324fa73c2 in std::__cxx11::basic_string<char, std::char_traits, std::allocator >::_M_assign(std::__cxx11::basic_string<char, std::char_traits, std::allocator > const&) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#2 0x00007f7324fa7b09 in std::__cxx11::basic_string<char, std::char_traits, std::allocator >::assign(std::__cxx11::basic_string<char, std::char_traits, std::allocator > const&) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3 0x0000000000755464 in RedisClient::<lambda(cpp_redis::reply&)>::operator()(cpp_redis::reply &) const (__closure=0x7f7314009a70,
reply=...) at /builds/edge/signaling-server/source/redisClient.cpp:998
#4 0x0000000000764d5f in std::_Function_handler<void(cpp_redis::reply&), RedisClient::getClientDetails(std::__cxx11::string*, std::__cxx11::string*, std::__cxx11::string*, std::__cxx11::string)::<lambda(cpp_redis::reply&)> >::_M_invoke(const std::_Any_data &, cpp_redis::reply &) (__functor=..., __args#0=...) at /usr/include/c++/5/functional:1871
#5 0x0000000000987d51 in cpp_redis::client::connection_receive_handler(cpp_redis::network::redis_connection&, cpp_redis::reply&) ()
#6 0x00000000009dee89 in cpp_redis::network::redis_connection::tcp_client_receive_handler(cpp_redis::network::tcp_client_iface::read_result const&) ()
#7 0x00000000009df6b8 in std::_Function_handler<void (tacopie::tcp_client::read_result&), cpp_redis::network::tcp_client::async_read(cpp_redis::network::tcp_client_iface::read_request&)::{lambda(tacopie::tcp_client::read_result&)#1}>::_M_invoke(std::_Any_data const&, tacopie::tcp_client::read_result&) ()
#8 0x00000000009e7184 in tacopie::tcp_client::on_read_available(int) ()
#9 0x00000000009e41fd in std::_Function_handler<void (), tacopie::io_service::process_rd_event(int const&, tacopie::io_service::tracked_socket&)::{lambda()#1}>::_M_invoke(std::_Any_data const&) ()
#10 0x00000000009ea8c6 in tacopie::utils::thread_pool::run() ()
#11 0x00007f7324f40c80 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#12 0x00007f732541c6ba in start_thread (arg=0x7f7323f7a700) at pthread_create.c:333
#13 0x00007f73246a641d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109

(gdb) fr 3
#3 0x0000000000755464 in RedisClient::<lambda(cpp_redis::reply&)>::operator()(cpp_redis::reply &) const (__closure=0x7f7314009a70,
reply=...) at /builds/edge/signaling-server/source/redisClient.cpp:998
998 /builds/edge/signaling-server/source/redisClient.cpp: No such file or directory.
(gdb) print reply
$1 = (cpp_redis::reply &) @0x7f7323f79cd0: {m_type = cpp_redis::reply::type::array, m_rows = std::vector of length 3, capacity 3 = {{
m_type = cpp_redis::reply::type::bulk_string, m_rows = std::vector of length 0, capacity 0,
m_str_val = "media:75177524-7cdb-4a23-9775-247cdb3a23ee:dev-e2:1-0-0", m_int_val = 140132233556400}, {
m_type = cpp_redis::reply::type::bulk_string, m_rows = std::vector of length 0, capacity 0,
m_str_val = "identity:cfa6dcdc-0ded-487f-a6dc-dc0ded487fb7:dev-e2:1-0-0", m_int_val = 140132233556400}, {
m_type = cpp_redis::reply::type::bulk_string, m_rows = std::vector of length 0, capacity 0,
m_str_val = "device:d76b8e07-f3c9-4fb8-ab8e-07f3c93fb8a0:dev-e2:1-0-0", m_int_val = 140132233556400}}, m_str_val = "",
m_int_val = 3906091140372838712}
(gdb)

Desktop (please complete the following information):

  • OS: Ubuntu 16.04

Can you provide an interface that calls back on the main thread?

Hello, I am a game server developer. When we use cpp_redis, there will be a need to call back on the main thread.

At present, I have sealed it with asio to temporarily meet the needs. Would like to ask if the official can provide such an interface. Or there are others with similar needs.
My own example: https://github.com/brinkqiang/dmredispp

#include <cpp_redis/cpp_redis>

#include <iostream>

#ifdef _WIN32
#include <Winsock2.h>
#endif /* _WIN32 */
#include "dmevent/dmevent_module.h"


int
main(void) {
#ifdef _WIN32
    //! Windows netword DLL init
    WORD version = MAKEWORD(2, 2);
    WSADATA data;

    if (WSAStartup(version, &data) != 0) {
        std::cerr << "WSAStartup() failure" << std::endl;
        return -1;
    }
#endif /* _WIN32 */

    DMEVENT_INIT();
    DMEVENT_BEGIN
    {
        fmt::print("-------------------------------------------- -------------------\n");
        fmt::print("{} dmevent loop {} ...\n", DMGetExeName(), "running");
        fmt::print("-------------------------------------------- -------------------\n");
    }
    DMEVENT_END;


    //! Enable logging
    cpp_redis::active_logger = std::unique_ptr<cpp_redis::logger>(new cpp_redis::logger);

    cpp_redis::client client;

    client.connect("127.0.0.1", 6379, [&](const std::string& host, std::size_t port, cpp_redis::client::connect_state status) {
        DMEVENT_BEGIN
        {
            if (status == cpp_redis::client::connect_state::dropped) {
                fmt::print("client disconnected from {}:{} isMain:{}\n", host, port, isMain());
            }
        }
        DMEVENT_END;
    });

    int roleid = 0x1234;
    // same as client. send({ "SET", "hello", "42" }, ...)
    client.set("hello", "42", [&](cpp_redis::reply& reply) {
        DMEVENT_BEGIN
        {
            fmt::print("set hello 42: {} roleid: {} isMain:{}\n", reply, roleid, isMain());
        }
        DMEVENT_END;
    });

    // same as client. send({ "DECRBY", "hello", 12 }, ...)
    client.decrby("hello", 12, [&](cpp_redis::reply& reply) {
        DMEVENT_BEGIN
        {
            fmt::print("decrby hello 12: {} roleid: {} isMain:{}\n", reply, roleid, isMain());
        }
        DMEVENT_END;
    });

    // same as client. send({ "GET", "hello" }, ...)
    client.get("hello", [&](cpp_redis::reply& reply) {
        DMEVENT_BEGIN
        {
            fmt::print("get hello: {} roleid: {} isMain:{}\n", reply, roleid, isMain());
        }
        DMEVENT_END;
    });

    // commands are pipelined and only sent when client.commit() is called
    client.commit();

    DMEVENT_RUN_UNTIL();
    // synchronous commit, no timeout
    //client.sync_commit();

    // synchronous commit, timeout
    // client.sync_commit(std::chrono::milliseconds(100));

#ifdef _WIN32
    WSACleanup();
#endif /* _WIN32 */

    return 0;
}

Async Connect

Is your feature request related to a problem? Please describe.
The tcp_client_iface class support asynchronous read and write, but async_connect and async_disconnect are not implemented. this forces the user to mix sync and async code, and synchronous reconnect is not suitable for many event-based applications

Describe the solution you'd like
Add async_connect and async_disconnect to the client

Describe alternatives you've considered
considered using synchronous connect and disconnect, but it blocks the other components on my event loop

Additional context
Using boost asio

fail Socket()

Hi there,
i've created a minimal c++17 project, to test the library on windows, but when i run the code from below i get the error fail Socket().

#include <iostream>
#include "cpp_redis/cpp_redis"

int main(int argc, char* argv[])
{
	try {
		cpp_redis::client client;
		client.connect();
	} catch(std::exception& e)
	{
		std::cout << e.what() << std::endl;
	}

	std::cin.get();
	return 0;
}

Project was generated using the following premake5 file:

project "test"
	language "C++"
	cppdialect "C++17"
	kind "ConsoleApp"

	libdirs { "lib" }

	vpaths {
		["Headers/*"] = "**.h",
		["Sources/*"] = "**.cpp",
		["Test files"] = "**.json",
		["*"] = "premake5.lua"
	}

	files {
		"premake5.lua",
		"**.cpp",
		"**.h",
	}

	filter { "system:windows", "platforms:x86" }
		links { "tacopie.lib" }
		links { "cpp_redis.lib" }
	
	filter { "system:windows", "platforms:x64" }
		links { "tacopie_64.lib" }
		links { "cpp_redis_64.lib" }

	filter "system:linux"

Error with Jan 21, 2017 C++17 bugfix

The bugfix to allow the use of the std::optional function from c++17 doesn't compile when building with c++17.
There is a hanging paren after the first #endif in optional.hpp, but in addition, the optional struct defines the bracket operator which is not defined on std::optional.
reply.cpp also didn't include the logger.hpp file containing the __CPP_REDIS_LOG macro.
Because of the std namespace override, the uses of the optional struct in the code needed to be replaced with optional_t.
Additionally, enableIf template needs to be added to the C++17 branch in optional.hpp.
Pull request incoming.

cpp_redis on windows-x86_64, WSACleanup function call causes abort()

WSACleanup function call raises abort() due to mutex destruction while it's locked.

Steps to reproduce:
Call WSACleanup() to terminate working with ws2_32.dll

I use VS 2017 ver 15.9.17
Code snippet what i am trying to do:

WORD version = MAKEWORD(2, 2);
WSADATA data;

if (WSAStartup(version, &data) != 0) {
    std::cerr << "WSAStartup() failure" << std::endl;
    return -1;
}
cpp_redis::client client;

client.connect(host, port, [](const std::string& host, std::size_t port, cpp_redis::client::connect_state status) {
    if (status == cpp_redis::client::connect_state::dropped) {
        std::cout << "client disconnected from " << host << ":" << port << std::endl;
    }
});

// .... some code here ....

client.sync_commit();
client.disconnect(true);

WSACleanup();

Output:
f:\dd\vctools\crt\crtw32\stdcpp\thr\mutex.c(51): mutex destroyed while busy

 issue_debug_notification(const wchar_t * const message) Line 28	C++
__acrt_report_runtime_error(const wchar_t * message) Line 154	C++
abort() Line 61	C++
[External Code]	
tacopie::io_service::~io_service() Line 85	C++
[External Code]	
_execute_onexit_table::__l2::<lambda>() Line 206	C++
__crt_seh_guarded_call<int>::operator()<void <lambda>(void),int <lambda>(void) & __ptr64,void <lambda>(void) >(__acrt_lock_and_call::__l2::void <lambda>(void) && setup, _execute_onexit_table::__l2::int <lambda>(void) & action, __acrt_lock_and_call::__l2::void <lambda>(void) && cleanup) Line 204	C++
__acrt_lock_and_call<int <lambda>(void) >(const __acrt_lock_id lock_id, _execute_onexit_table::__l2::int <lambda>(void) && action) Line 940	C++
_execute_onexit_table(_onexit_table_t * table) Line 231	C++

Removing the WSACleanup() call helps to avoid the crash, but it causes memory leaks.
Several questions:

  1. Is it known about this issue and how to eliminate it ?
  2. Why after disconnect(true) call the WSACleanup() causes abort() ? Does tacopie::io_service finish client's socket connections after disconnect(true) call ?

Expected behavior:
Release resources and finish program execution without any abort() calls

Desktop:

  • OS: windows 10 19h1_release

undefined reference to `operator<<(std::ostream&, cpp_redis::reply const&)'

I followed the installation procedure (https://github.com/Cylix/cpp_redis/wiki/Mac-&-Linux-Install), using the updated library instead of the old one:

# ... rest of procedure described in link
git clone https://github.com/cpp-redis/cpp_redis.git
# ... rest of procedure described in link

Now when I try to run a program (even

cpp_redis_client.cpp

in the example dir) I got the error:

/tmp/ccptfGnr.o: In function `main::{lambda(cpp_redis::reply&)#1}::operator()(cpp_redis::reply&) const':
ex0.cpp:(.text+0xc5): undefined reference to `operator<<(std::ostream&, cpp_redis::reply const&)'
/tmp/ccptfGnr.o: In function `main':
ex0.cpp:(.text+0x105): undefined reference to `cpp_redis::client::client()'
ex0.cpp:(.text+0x17c): undefined reference to `cpp_redis::client::connect(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long, std::function<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long, cpp_redis::connect_state)> const&, unsigned int, int, unsigned int)'
ex0.cpp:(.text+0x223): undefined reference to `cpp_redis::client::set(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
ex0.cpp:(.text+0x2bd): undefined reference to `cpp_redis::client::get(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::function<void (cpp_redis::reply&)> const&)'
ex0.cpp:(.text+0x2f0): undefined reference to `cpp_redis::client::sync_commit()'
ex0.cpp:(.text+0x304): undefined reference to `cpp_redis::client::~client()'
ex0.cpp:(.text+0x3ca): undefined reference to `cpp_redis::client::~client()'
collect2: error: ld returned 1 exit status

I tried with#include <iostream>but nothing worked.

Here my code:

#include <string>
#include <cpp_redis/cpp_redis>
#include <cpp_redis/misc/macro.hpp>
#include <iostream>

/*
to compile:
gcc -lstdc++ --std=c++11  \
    ex0.cpp \
    -o ex0 \
    && time ./ex0
*/

int main(int argc, char const *argv[]) {

//    cpp_redis::active_logger = std::unique_ptr<cpp_redis::logger>(new cpp_redis::logger);

    cpp_redis::client client;

    client.connect();

    client.set("hello", "42");
    client.get("hello", [](cpp_redis::reply& reply) {
      std::cout << reply << std::endl;
    });
    //! also support std::future
    //! std::future<cpp_redis::reply> get_reply = client.get("hello");

    client.sync_commit();
    //! or client.commit(); for asynchronous call

    return 0;
}

Compiled through gcc:
gcc -lstdc++ --std=c++11 ex0.cpp -o ex0
Thanks a lot in advance for any help!

New release version

Last release version on this library is 4.3.1 dated Feb 1, 2018.

Please create a new Release tag.

Thanks

get error when reply.as_string() ,macos 10.15 compile by bazel

Describe the bug
A clear and concise description of what the bug is.
i use bazel compile my project. below is my code


       cpp_redis::client client;

	client.connect("127.0.0.1", 6379);
	client.auth("123456");

	std::future<cpp_redis::reply> r2= client.get("hello");
	client.sync_commit();
	if(r2.get().is_null()){
		cout << "null" << endl;
	}
	else{
		cout << "123" << endl;
		cout << r2.get().as_string()<< endl;
		cout << "456" << endl;
	}

WORKSPACE

http_archive(
    name = "redis",
    strip_prefix = "cpp_redis-master",
    url = "https://github.com/cpp-redis/cpp_redis/archive/master.zip",
)

load("@redis//:repositories.bzl", "cpp_redis_repositories")

cpp_redis_repositories()

BUILD

cc_binary(
    name = "wasm",
    srcs = ["seclang.cpp"],
    deps = [
    	"@redis//:cpp_redis",
    	":t1"
    	
    ],
    visibility = ["//visibility:public"]
)

cc_library(
    name = "t1",
    srcs = ["ttt/t1.cpp"],
    hdrs = ["ttt/t1.h"]
)

build

bazel build -s //src:wasm

In file included from bazel-out/darwin-fastbuild/bin/external/redis/_virtual_includes/cpp_redis/cpp_redis/core/reply.hpp:29:
In file included from bazel-out/darwin-fastbuild/bin/external/redis/_virtual_includes/cpp_redis/cpp_redis/misc/optional.hpp:39:
bazel-out/darwin-fastbuild/bin/external/redis/_virtual_includes/cpp_redis/cpp_redis/misc/logger.hpp:135:3: warning: explicitly defaulted copy constructor is implicitly deleted [-Wdefaulted-function-deleted]
  logger(const logger&) = default;
  ^
bazel-out/darwin-fastbuild/bin/external/redis/_virtual_includes/cpp_redis/cpp_redis/misc/logger.hpp:194:14: note: copy constructor of 'logger' is implicitly deleted because field 'm_mutex' has a deleted copy constructor
  std::mutex m_mutex;
             ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__mutex_base:40:5: note: 'mutex' has been explicitly marked deleted here
    mutex(const mutex&) = delete;
    ^
In file included from src/seclang.cpp:11:
In file included from bazel-out/darwin-fastbuild/bin/external/redis/_virtual_includes/cpp_redis/cpp_redis/cpp_redis:30:
In file included from bazel-out/darwin-fastbuild/bin/external/redis/_virtual_includes/cpp_redis/cpp_redis/core/client.hpp:36:
In file included from bazel-out/darwin-fastbuild/bin/external/redis/_virtual_includes/cpp_redis/cpp_redis/core/types.hpp:31:
In file included from bazel-out/darwin-fastbuild/bin/external/redis/_virtual_includes/cpp_redis/cpp_redis/core/reply.hpp:29:
In file included from bazel-out/darwin-fastbuild/bin/external/redis/_virtual_includes/cpp_redis/cpp_redis/misc/optional.hpp:39:
bazel-out/darwin-fastbuild/bin/external/redis/_virtual_includes/cpp_redis/cpp_redis/misc/logger.hpp:140:11: warning: explicitly defaulted copy assignment operator is implicitly deleted [-Wdefaulted-function-deleted]
  logger& operator=(const logger&) = default;
          ^
bazel-out/darwin-fastbuild/bin/external/redis/_virtual_includes/cpp_redis/cpp_redis/misc/logger.hpp:194:14: note: copy assignment operator of 'logger' is implicitly deleted because field 'm_mutex' has a deleted copy assignment operator
  std::mutex m_mutex;
             ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__mutex_base:41:12: note: 'operator=' has been explicitly marked deleted here
    mutex& operator=(const mutex&) = delete;
           ^
In file included from src/seclang.cpp:11:
In file included from bazel-out/darwin-fastbuild/bin/external/redis/_virtual_includes/cpp_redis/cpp_redis/cpp_redis:41:
In file included from bazel-out/darwin-fastbuild/bin/external/redis/_virtual_includes/cpp_redis/cpp_redis/network/tcp_client.hpp:28:
In file included from bazel-out/darwin-fastbuild/bin/external/tacopie/_virtual_includes/tacopie/tacopie/tacopie:30:
In file included from bazel-out/darwin-fastbuild/bin/external/tacopie/_virtual_includes/tacopie/tacopie/utils/error.hpp:29:
bazel-out/darwin-fastbuild/bin/external/tacopie/_virtual_includes/tacopie/tacopie/utils/logger.hpp:107:3: warning: explicitly defaulted copy constructor is implicitly deleted [-Wdefaulted-function-deleted]
  logger(const logger&) = default;
  ^
bazel-out/darwin-fastbuild/bin/external/tacopie/_virtual_includes/tacopie/tacopie/utils/logger.hpp:157:14: note: copy constructor of 'logger' is implicitly deleted because field 'm_mutex' has a deleted copy constructor
  std::mutex m_mutex;
             ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__mutex_base:40:5: note: 'mutex' has been explicitly marked deleted here
    mutex(const mutex&) = delete;
    ^
In file included from src/seclang.cpp:11:
In file included from bazel-out/darwin-fastbuild/bin/external/redis/_virtual_includes/cpp_redis/cpp_redis/cpp_redis:41:
In file included from bazel-out/darwin-fastbuild/bin/external/redis/_virtual_includes/cpp_redis/cpp_redis/network/tcp_client.hpp:28:
In file included from bazel-out/darwin-fastbuild/bin/external/tacopie/_virtual_includes/tacopie/tacopie/tacopie:30:
In file included from bazel-out/darwin-fastbuild/bin/external/tacopie/_virtual_includes/tacopie/tacopie/utils/error.hpp:29:
bazel-out/darwin-fastbuild/bin/external/tacopie/_virtual_includes/tacopie/tacopie/utils/logger.hpp:109:11: warning: explicitly defaulted copy assignment operator is implicitly deleted [-Wdefaulted-function-deleted]
  logger& operator=(const logger&) = default;
          ^
bazel-out/darwin-fastbuild/bin/external/tacopie/_virtual_includes/tacopie/tacopie/utils/logger.hpp:157:14: note: copy assignment operator of 'logger' is implicitly deleted because field 'm_mutex' has a deleted copy assignment operator
  std::mutex m_mutex;
             ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__mutex_base:41:12: note: 'operator=' has been explicitly marked deleted here
    mutex& operator=(const mutex&) = delete;
           ^
4 warnings generated.
Target //src:wasm up-to-date:
  bazel-bin/src/wasm
INFO: Elapsed time: 0.881s, Critical Path: 0.81s
INFO: 2 processes: 1 internal, 1 darwin-sandbox.
INFO: Build completed successfully, 2 total actions

run


dengxiaoqian@dengxiaoqiandeMacBook-Pro ctgw_wasm % bazel run -s //src:wasm
DEBUG: Rule 'redis' indicated that a canonical reproducible form can be obtained by modifying arguments sha256 = "666243fefb1465c0f9e6cd7fba0eab099e8aa7469674fecfc246f572705543ab"
DEBUG: Repository redis instantiated at:
  no stack (--record_rule_instantiation_callstack not enabled)
Repository rule http_archive defined at:
  /private/var/tmp/_bazel_dengxiaoqian/52cacb9c84a09b383e18d0ecdbf561f4/external/bazel_tools/tools/build_defs/repo/http.bzl:336:31: in <toplevel>
INFO: Analyzed target //src:wasm (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //src:wasm up-to-date:
  bazel-bin/src/wasm
INFO: Elapsed time: 0.077s, Critical Path: 0.00s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total action
INFO: Build completed successfully, 1 total action
!!!Hello World111!!!
123

console not print the value of 'hello' and '456'

what cause the problem?

Cannot make successfully with -DLOGGING_ENABLED=1 : "error: expected unqualified-id"

cpp-redis version : master 99b1dda

Describe the bug
I'm following the build instructions here: https://github.com/cpp-redis/cpp_redis/wiki/Mac-&-Linux-Install
With the logging enabled flag as described here: https://github.com/cpp-redis/cpp_redis/wiki/Compilation-and-installation-options#enable-logging

The make step fails with:

In file included from /Users/marwhal/Desktop/cpp_redis/sources/builders/array_builder.cpp:23:
In file included from /Users/marwhal/Desktop/cpp_redis/includes/cpp_redis/builders/array_builder.hpp:26:
In file included from /Users/marwhal/Desktop/cpp_redis/includes/cpp_redis/builders/builder_iface.hpp:29:
In file included from /Users/marwhal/Desktop/cpp_redis/includes/cpp_redis/core/reply.hpp:29:
/Users/marwhal/Desktop/cpp_redis/includes/cpp_redis/misc/optional.hpp:59:21: error: expected unqualified-id
    __CPP_REDIS_LOG(1, "value_or(U&& v)\n")
                    ^
2 warnings and 1 error generated.
make[2]: *** [CMakeFiles/cpp_redis.dir/sources/builders/array_builder.cpp.o] Error 1
make[1]: *** [CMakeFiles/cpp_redis.dir/all] Error 2

Versions:

โžœ  build git:(master) gcc --version
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 11.0.3 (clang-1103.0.32.59)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.