From 9ab996ca120cdf76141131156cad4706052bfdd3 Mon Sep 17 00:00:00 2001 From: Alex Nekipelov Date: Fri, 30 Jan 2015 17:01:53 +0300 Subject: [PATCH 01/21] New version --- .gitignore | 1 - .travis.yml | 11 +- Makefile | 6 +- README.md | 2 +- examples/Makefile | 38 +-- examples/async_pubsub.cpp | 64 +++++ examples/{example1.cpp => async_set_get.cpp} | 10 +- examples/{example5.cpp => async_set_get2.cpp} | 7 +- examples/example2.cpp | 38 --- examples/example3.cpp | 41 --- examples/example4.cpp | 61 ----- examples/sync_set_get.cpp | 66 +++++ .../{redisclient.cpp => redisasyncclient.cpp} | 102 +++---- src/redisclient/impl/redisclientimpl.cpp | 85 +++++- src/redisclient/impl/redisclientimpl.h | 9 +- src/redisclient/impl/redissyncclient.cpp | 255 ++++++++++++++++++ src/redisclient/redisasyncclient.h | 159 +++++++++++ src/redisclient/redisbuffer.h | 64 +++++ src/redisclient/redisclient.h | 137 +--------- src/redisclient/redissyncclient.h | 98 +++++++ src/redisclient/version.h | 2 +- 21 files changed, 869 insertions(+), 387 deletions(-) create mode 100644 examples/async_pubsub.cpp rename examples/{example1.cpp => async_set_get.cpp} (85%) rename examples/{example5.cpp => async_set_get2.cpp} (88%) delete mode 100644 examples/example2.cpp delete mode 100644 examples/example3.cpp delete mode 100644 examples/example4.cpp create mode 100644 examples/sync_set_get.cpp rename src/redisclient/impl/{redisclient.cpp => redisasyncclient.cpp} (71%) create mode 100644 src/redisclient/impl/redissyncclient.cpp create mode 100644 src/redisclient/redisasyncclient.h create mode 100644 src/redisclient/redisbuffer.h create mode 100644 src/redisclient/redissyncclient.h diff --git a/.gitignore b/.gitignore index 0b7b86d..03139c9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -# Qt Creator files *.o *.so examples/example[1-4] diff --git a/.travis.yml b/.travis.yml index df70de7..347031c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,16 @@ language: cpp compiler: - gcc +before_install: + - if [ "$CXX" == "g++" ]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; fi + - sudo apt-get update -qq + +install: + - if [ "$CXX" == "g++" ]; then sudo apt-get install -qq g++-4.8; fi + - if [ "$CXX" == "g++" ]; then sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50; fi + before_script: - sudo apt-get install -qq libboost-dev libboost-test-dev libboost-system-dev -script: make && make test && make -C examples example1 +script: + - make && make test && make -C examples diff --git a/Makefile b/Makefile index 7b91ade..de62b29 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,11 @@ -SRCS = src/redisclient/impl/redisclient.cpp src/redisclient/impl/redisvalue.cpp src/redisclient/impl/redisparser.cpp -HDRS = src/redisclient.h src/redisvalie.h src/redisparser.h +SRCS = src/redisclient/impl/redissyncclient.cpp src/redisclient/impl/redisasyncclient.cpp src/redisclient/impl/redisvalue.cpp src/redisclient/impl/redisparser.cpp +HDRS = src/redisasyncclient.h src/redissyncclient.h src/redisvalie.h src/redisparser.h OBJS = $(SRCS:.cpp=.o) LIBNAME = redisclient LIB = lib$(LIBNAME).so LIBS = -pthread -lboost_system LDFLAGS = -g -shared -CXXFLAGS = -g -O2 -Wall -Wextra -fPIC -std=c++0x -DREDIS_CLIENT_DYNLIB -DREDIS_CLIENT_BUILD +CXXFLAGS = -g -O2 -Wall -Wextra -fPIC -std=c++11 -DREDIS_CLIENT_DYNLIB -DREDIS_CLIENT_BUILD all: test dynlib: $(LIB) diff --git a/README.md b/README.md index 3bb6a75..6480e2d 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ redisclient Build status: [![Build Status](https://travis-ci.org/nekipelov/redisclient.svg?branch=master)](https://travis-ci.org/nekipelov/redisclient) -Current version: 0.3.2 +Current version: 0.4.0 Boost.asio based Redis-client header-only library. Simple but powerfull. diff --git a/examples/Makefile b/examples/Makefile index 9ad143f..c801559 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -1,32 +1,22 @@ -LIBS = -lboost_system -LDFLAGS = -g -L.. -pthread -CXXFLAGS = -g -O2 -Wall -Wextra -I../src -CXX11FLAGS = -g -O2 -std=c++11 -Wall -Wextra -I../src +LDFLAGS = -g -pthread -lboost_system +CXXFLAGS = -g -O2 -Wall -Wextra -I../src -std=c++11 -all: examples -examples: example1 example2 example3 example4 example5 +EXAMPLES = async_pubsub async_set_get async_set_get2 sync_set_get +SOURCES = $(EXAMPLES:=.cpp) +OBJS = $(SOURCES:.cpp=.o) +DEPS = $(SOURCES:.cpp=.d) -example1: $(OBJS) example1.o - $(CXX) $^ -o $@ $(LDFLAGS) $(LIBS) -example1.o: example1.cpp - $(CXX) $(CXXFLAGS) -c $< -o $@ +all: $(EXAMPLES) -example2: $(OBJS) example2.o - $(CXX) $^ -o $@ $(LDFLAGS) $(LIBS) +$(EXAMPLES): $(OBJS) + $(CXX) $(LDFLAGS) $@.o -o $@ -example3: $(OBJS) example3.o - $(CXX) $^ -o $@ $(LDFLAGS) $(LIBS) - -example4: $(OBJS) example4.o - $(CXX) $^ -o $@ $(LDFLAGS) $(LIBS) - -example5: $(OBJS) example5.o - $(CXX) $^ -o $@ $(LDFLAGS) $(LIBS) - %.o: %.cpp - $(CXX) $(CXX11FLAGS) -c $< -o $@ + $(CXX) $(CXXFLAGS) -MMD -c $< -o $@ clean: - rm -f $(OBJS) example1.o example1 example2.o example2 example3.o example3 example4.o example4 example5.o example5 + rm -f $(OBJS) $(EXAMPLES) $(DEPS) + +-include $(DEPS) -.PHONY: all examples clean +.PHONY: clean diff --git a/examples/async_pubsub.cpp b/examples/async_pubsub.cpp new file mode 100644 index 0000000..7123716 --- /dev/null +++ b/examples/async_pubsub.cpp @@ -0,0 +1,64 @@ +#include +#include +#include +#include + +#include + +static const std::string channelName = "unique-redis-channel-name-example"; + +void subscribeHandler(boost::asio::io_service &ioService, const std::string &msg) +{ + std::cerr << "Message: " << msg << std::endl; + + if( msg == "stop" ) + ioService.stop(); +} + +void publishHandler(RedisAsyncClient &publisher, const RedisValue &) +{ + publisher.publish(channelName, "First hello", [&](const RedisValue &) { + publisher.publish(channelName, "Last hello", [&](const RedisValue &) { + publisher.publish(channelName, "stop"); + }); + }); +} + +int main(int, char **) +{ + boost::asio::ip::address address = boost::asio::ip::address::from_string("127.0.0.1"); + const unsigned short port = 6379; + + boost::asio::io_service ioService; + RedisAsyncClient publisher(ioService); + RedisAsyncClient subscriber(ioService); + + + publisher.asyncConnect(address, port, [&](bool status, const std::string &err) + { + if( !status ) + { + std::cerr << "Can't connect to to redis" << err << std::endl; + } + else + { + subscriber.asyncConnect(address, port, [&](bool status, const std::string &err) + { + if( !status ) + { + std::cerr << "Can't connect to to redis" << err << std::endl; + } + else + { + subscriber.subscribe(channelName, + boost::bind(&subscribeHandler, boost::ref(ioService), _1), + boost::bind(&publishHandler, boost::ref(publisher), _1)); + } + }); + } + }); + + ioService.run(); + + return 0; +} diff --git a/examples/example1.cpp b/examples/async_set_get.cpp similarity index 85% rename from examples/example1.cpp rename to examples/async_set_get.cpp index 8b0c820..56032d0 100644 --- a/examples/example1.cpp +++ b/examples/async_set_get.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include static const std::string redisKey = "unique-redis-key-example"; static const std::string redisValue = "unique-redis-value"; @@ -11,7 +11,7 @@ static const std::string redisValue = "unique-redis-value"; class Worker { public: - Worker(boost::asio::io_service &ioService, RedisClient &redisClient) + Worker(boost::asio::io_service &ioService, RedisAsyncClient &redisClient) : ioService(ioService), redisClient(redisClient) {} @@ -22,7 +22,7 @@ class Worker private: boost::asio::io_service &ioService; - RedisClient &redisClient; + RedisAsyncClient &redisClient; }; void Worker::onConnect(bool connected, const std::string &errorMessage) @@ -40,6 +40,7 @@ void Worker::onConnect(bool connected, const std::string &errorMessage) void Worker::onSet(const RedisValue &value) { + std::cerr << "SET: " << value.toString() << std::endl; if( value.toString() == "OK" ) { redisClient.command("GET", redisKey, @@ -53,6 +54,7 @@ void Worker::onSet(const RedisValue &value) void Worker::onGet(const RedisValue &value) { + std::cerr << "GET " << value.toString() << std::endl; if( value.toString() != redisValue ) { std::cerr << "Invalid value from redis: " << value.toString() << std::endl; @@ -69,7 +71,7 @@ int main(int, char **) const int port = 6379; boost::asio::io_service ioService; - RedisClient client(ioService); + RedisAsyncClient client(ioService); Worker worker(ioService, client); boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(address), port); diff --git a/examples/example5.cpp b/examples/async_set_get2.cpp similarity index 88% rename from examples/example5.cpp rename to examples/async_set_get2.cpp index eed5348..791001d 100644 --- a/examples/example5.cpp +++ b/examples/async_set_get2.cpp @@ -2,12 +2,13 @@ #include #include #include -#include + +#include static const std::string redisKey = "unique-redis-key-example"; static const std::string redisValue = "unique-redis-value"; -void handleConnected(boost::asio::io_service &ioService, RedisClient &redis, +void handleConnected(boost::asio::io_service &ioService, RedisAsyncClient &redis, bool ok, const std::string &errmsg) { if( ok ) @@ -36,7 +37,7 @@ int main(int, char **) const unsigned short port = 6379; boost::asio::io_service ioService; - RedisClient redis(ioService); + RedisAsyncClient redis(ioService); redis.asyncConnect(address, port, boost::bind(&handleConnected, boost::ref(ioService), boost::ref(redis), _1, _2)); diff --git a/examples/example2.cpp b/examples/example2.cpp deleted file mode 100644 index 0c70427..0000000 --- a/examples/example2.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include -#include - -static const std::string redisKey = "unique-redis-key-example"; -static const std::string redisValue = "unique-redis-value"; - -int main(int, char **) -{ - boost::asio::ip::address address = boost::asio::ip::address::from_string("127.0.0.1"); - const unsigned short port = 6379; - - boost::asio::io_service ioService; - RedisClient redis(ioService); - - if( !redis.connect(address, port) ) - { - std::cerr << "Can't connecto to redis" << std::endl; - return EXIT_FAILURE; - } - - redis.command("SET", redisKey, redisValue, [&](const RedisValue &v) { - std::cerr << "SET: " << v.toString() << std::endl; - - redis.command("GET", redisKey, [&](const RedisValue &v) { - std::cerr << "GET: " << v.toString() << std::endl; - - redis.command("DEL", redisKey, [&](const RedisValue &) { - ioService.stop(); - }); - }); - }); - - ioService.run(); - - return 0; -} diff --git a/examples/example3.cpp b/examples/example3.cpp deleted file mode 100644 index 5be2a6a..0000000 --- a/examples/example3.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -#include -#include - -#include - -static const std::string channelName = "unique-redis-channel-name-example"; - -int main(int, char **) -{ - boost::asio::ip::address address = boost::asio::ip::address::from_string("127.0.0.1"); - const unsigned short port = 6379; - - boost::asio::io_service ioService; - RedisClient publisher(ioService); - RedisClient subscriber(ioService); - - if( !publisher.connect(address, port) || !subscriber.connect(address, port) ) - { - std::cerr << "Can't connecto to redis" << std::endl; - return EXIT_FAILURE; - } - - subscriber.subscribe(channelName, [&](const std::string &msg) { - std::cerr << "Message: " << msg << std::endl; - - if( msg == "stop" ) - ioService.stop(); - }); - - publisher.publish(channelName, "First hello", [&](const RedisValue &) { - publisher.publish(channelName, "Last hello", [&](const RedisValue &) { - publisher.publish(channelName, "stop"); - }); - }); - - ioService.run(); - - return 0; -} diff --git a/examples/example4.cpp b/examples/example4.cpp deleted file mode 100644 index 8c1711a..0000000 --- a/examples/example4.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include -#include -#include -#include // for boost::crc_32_type - -#include - - -#include - -static const std::string channelName = "unique-redis-channel-name-example"; - -int main(int, char **) -{ - boost::asio::ip::address address = boost::asio::ip::address::from_string("127.0.0.1"); - const unsigned short port = 6379; - - boost::asio::io_service ioService; - RedisClient publisher(ioService); - RedisClient subscriber(ioService); - - if( !publisher.connect(address, port) || !subscriber.connect(address, port) ) - { - std::cerr << "Can't connecto to redis" << std::endl; - return EXIT_FAILURE; - } - - size_t expectedCrc = 0; - - subscriber.subscribe(channelName, [&](const std::string &msg) { - boost::crc_32_type crc32; - crc32.process_bytes(msg.c_str(), msg.size()); - size_t checksum = crc32.checksum(); - - if( checksum != expectedCrc ) - std::cerr << "fail" << std::endl; - else - std::cerr << "ok" << std::endl; - ioService.stop(); - }); - - ioService.poll(); - - size_t size = 200000; - std::string msg; - - - for(size_t i = 0; i < size; ++i) - msg += (boost::format("Hello! Message number %1%") % i).str(); - - boost::crc_32_type crc32; - crc32.process_bytes(msg.c_str(), msg.size()); - expectedCrc = crc32.checksum(); - - publisher.publish(channelName, msg, [&](const RedisValue &) {}); - - ioService.run(); - - return 0; -} diff --git a/examples/sync_set_get.cpp b/examples/sync_set_get.cpp new file mode 100644 index 0000000..a896ae6 --- /dev/null +++ b/examples/sync_set_get.cpp @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include +#include + +int main(int, char **) +{ + boost::asio::ip::address address = boost::asio::ip::address::from_string("127.0.0.1"); + const unsigned short port = 6379; + + boost::asio::io_service ioService; + RedisSyncClient redis(ioService); + std::string errmsg; + + if( !redis.connect(address, port, errmsg) ) + { + std::cerr << "Can't connect to redis: " << errmsg << std::endl; + return EXIT_FAILURE; + } + + const std::string key = "unique-redis-key-example"; + const char rawValue [] = "unique-redis-value"; + const std::string stringValue(rawValue, rawValue + sizeof(rawValue)); + const std::vector vectorValue(rawValue, rawValue + sizeof(rawValue)); + + { + // raw + redis.command("SET", key, rawValue); + RedisValue value = redis.command("GET", key); + + if( value.toString() != rawValue ) + { + std::cerr << "Invalid value from redis: " << value.toString() << std::endl; + return EXIT_FAILURE; + } + } + + { + // std::string + redis.command("SET", key, stringValue); + RedisValue value = redis.command("GET", key); + + if( value.toString() != stringValue ) + { + std::cerr << "Invalid value from redis: " << value.toString() << std::endl; + return EXIT_FAILURE; + } + } + + { + // vector + redis.command("SET", key, vectorValue); + RedisValue value = redis.command("GET", key); + /* + if( value.toString() != vectorValue ) + { + std::cerr << "Invalid value from redis: " << value.toString() << std::endl; + return EXIT_FAILURE; + } + * */ + } + + return EXIT_SUCCESS; +} diff --git a/src/redisclient/impl/redisclient.cpp b/src/redisclient/impl/redisasyncclient.cpp similarity index 71% rename from src/redisclient/impl/redisclient.cpp rename to src/redisclient/impl/redisasyncclient.cpp index 9f00ebe..06ee8e6 100644 --- a/src/redisclient/impl/redisclient.cpp +++ b/src/redisclient/impl/redisasyncclient.cpp @@ -3,53 +3,33 @@ * License: MIT */ -#ifndef REDISCLIENT_REDISCLIENT_CPP -#define REDISCLIENT_REDISCLIENT_CPP +#ifndef REDISASYNCCLIENT_REDISASYNCCLIENT_CPP +#define REDISASYNCCLIENT_REDISASYNCCLIENT_CPP #include #include "../redisclient.h" -RedisClient::RedisClient(boost::asio::io_service &ioService) +RedisAsyncClient::RedisAsyncClient(boost::asio::io_service &ioService) : pimpl(boost::make_shared(boost::ref(ioService))) { pimpl->errorHandler = boost::bind(&RedisClientImpl::defaulErrorHandler, pimpl, _1); } -RedisClient::~RedisClient() +RedisAsyncClient::~RedisAsyncClient() { pimpl->close(); } -bool RedisClient::connect(const boost::asio::ip::address &address, - unsigned short port) -{ - boost::asio::ip::tcp::endpoint endpoint(address, port); - boost::system::error_code ec; - - pimpl->socket.connect(endpoint, ec); - - if( !ec ) - { - pimpl->state = RedisClientImpl::Connected; - pimpl->processMessage(); - return true; - } - else - { - return false; - } -} - -void RedisClient::asyncConnect(const boost::asio::ip::address &address, +void RedisAsyncClient::connect(const boost::asio::ip::address &address, unsigned short port, const boost::function &handler) { boost::asio::ip::tcp::endpoint endpoint(address, port); - asyncConnect(endpoint, handler); + connect(endpoint, handler); } -void RedisClient::asyncConnect(const boost::asio::ip::tcp::endpoint &endpoint, +void RedisAsyncClient::connect(const boost::asio::ip::tcp::endpoint &endpoint, const boost::function &handler) { pimpl->socket.async_connect(endpoint, boost::bind(&RedisClientImpl::handleAsyncConnect, @@ -57,24 +37,24 @@ void RedisClient::asyncConnect(const boost::asio::ip::tcp::endpoint &endpoint, } -void RedisClient::installErrorHandler( +void RedisAsyncClient::installErrorHandler( const boost::function &handler) { pimpl->errorHandler = handler; } -void RedisClient::command(const std::string &s, const boost::function &handler) +void RedisAsyncClient::command(const std::string &s, const boost::function &handler) { if(stateValid()) { std::vector items(1); items[0] = s; - pimpl->post(boost::bind(&RedisClientImpl::doCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); } } -void RedisClient::command(const std::string &cmd, const std::string &arg1, +void RedisAsyncClient::command(const std::string &cmd, const std::string &arg1, const boost::function &handler) { if(stateValid()) @@ -83,11 +63,11 @@ void RedisClient::command(const std::string &cmd, const std::string &arg1, items[0] = cmd; items[1] = arg1; - pimpl->post(boost::bind(&RedisClientImpl::doCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); } } -void RedisClient::command(const std::string &cmd, const std::string &arg1, +void RedisAsyncClient::command(const std::string &cmd, const std::string &arg1, const std::string &arg2, const boost::function &handler) { @@ -98,11 +78,11 @@ void RedisClient::command(const std::string &cmd, const std::string &arg1, items[1] = arg1; items[2] = arg2; - pimpl->post(boost::bind(&RedisClientImpl::doCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); } } -void RedisClient::command(const std::string &cmd, const std::string &arg1, +void RedisAsyncClient::command(const std::string &cmd, const std::string &arg1, const std::string &arg2, const std::string &arg3, const boost::function &handler) { @@ -114,11 +94,11 @@ void RedisClient::command(const std::string &cmd, const std::string &arg1, items[2] = arg2; items[3] = arg3; - pimpl->post(boost::bind(&RedisClientImpl::doCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); } } -void RedisClient::command(const std::string &cmd, const std::string &arg1, +void RedisAsyncClient::command(const std::string &cmd, const std::string &arg1, const std::string &arg2, const std::string &arg3, const std::string &arg4, const boost::function &handler) @@ -132,11 +112,11 @@ void RedisClient::command(const std::string &cmd, const std::string &arg1, items[3] = arg3; items[4] = arg4; - pimpl->post(boost::bind(&RedisClientImpl::doCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); } } -void RedisClient::command(const std::string &cmd, const std::string &arg1, +void RedisAsyncClient::command(const std::string &cmd, const std::string &arg1, const std::string &arg2, const std::string &arg3, const std::string &arg4, const std::string &arg5, const boost::function &handler) @@ -151,11 +131,11 @@ void RedisClient::command(const std::string &cmd, const std::string &arg1, items[4] = arg4; items[5] = arg5; - pimpl->post(boost::bind(&RedisClientImpl::doCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); } } -void RedisClient::command(const std::string &cmd, const std::string &arg1, +void RedisAsyncClient::command(const std::string &cmd, const std::string &arg1, const std::string &arg2, const std::string &arg3, const std::string &arg4, const std::string &arg5, const std::string &arg6, @@ -172,11 +152,11 @@ void RedisClient::command(const std::string &cmd, const std::string &arg1, items[5] = arg5; items[6] = arg6; - pimpl->post(boost::bind(&RedisClientImpl::doCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); } } -void RedisClient::command(const std::string &cmd, const std::string &arg1, +void RedisAsyncClient::command(const std::string &cmd, const std::string &arg1, const std::string &arg2, const std::string &arg3, const std::string &arg4, const std::string &arg5, const std::string &arg6, const std::string &arg7, @@ -194,11 +174,11 @@ void RedisClient::command(const std::string &cmd, const std::string &arg1, items[6] = arg6; items[7] = arg7; - pimpl->post(boost::bind(&RedisClientImpl::doCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); } } -void RedisClient::command(const std::string &cmd, const std::list &args, +void RedisAsyncClient::command(const std::string &cmd, const std::list &args, const boost::function &handler) { if(stateValid()) @@ -209,11 +189,11 @@ void RedisClient::command(const std::string &cmd, const std::list & items.reserve(1 + args.size()); std::copy(args.begin(), args.end(), std::back_inserter(items)); - pimpl->post(boost::bind(&RedisClientImpl::doCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); } } -RedisClient::Handle RedisClient::subscribe( +RedisAsyncClient::Handle RedisAsyncClient::subscribe( const std::string &channel, const boost::function &msgHandler, const boost::function &handler) @@ -231,7 +211,7 @@ RedisClient::Handle RedisClient::subscribe( items[0] = subscribe; items[1] = channel; - pimpl->post(boost::bind(&RedisClientImpl::doCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); pimpl->msgHandlers.insert(std::make_pair(channel, std::make_pair(handle.id, msgHandler))); pimpl->state = RedisClientImpl::Subscribed; @@ -241,7 +221,7 @@ RedisClient::Handle RedisClient::subscribe( { std::stringstream ss; - ss << "RedisClient::command called with invalid state " + ss << "RedisAsyncClient::command called with invalid state " << pimpl->state; pimpl->errorHandler(ss.str()); @@ -249,7 +229,7 @@ RedisClient::Handle RedisClient::subscribe( } } -void RedisClient::unsubscribe(const Handle &handle) +void RedisAsyncClient::unsubscribe(const Handle &handle) { #ifdef DEBUG static int recursion = 0; @@ -285,13 +265,13 @@ void RedisClient::unsubscribe(const Handle &handle) items[1] = handle.channel; // Unsubscribe command for Redis - pimpl->post(boost::bind(&RedisClientImpl::doCommand, pimpl, items, dummyHandler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, dummyHandler)); } else { std::stringstream ss; - ss << "RedisClient::command called with invalid state " + ss << "RedisAsyncClient::command called with invalid state " << pimpl->state; #ifdef DEBUG @@ -306,7 +286,7 @@ void RedisClient::unsubscribe(const Handle &handle) #endif } -void RedisClient::singleShotSubscribe(const std::string &channel, +void RedisAsyncClient::singleShotSubscribe(const std::string &channel, const boost::function &msgHandler, const boost::function &handler) { @@ -322,7 +302,7 @@ void RedisClient::singleShotSubscribe(const std::string &channel, items[0] = subscribe; items[1] = channel; - pimpl->post(boost::bind(&RedisClientImpl::doCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); pimpl->singleShotMsgHandlers.insert(std::make_pair(channel, msgHandler)); pimpl->state = RedisClientImpl::Subscribed; } @@ -330,7 +310,7 @@ void RedisClient::singleShotSubscribe(const std::string &channel, { std::stringstream ss; - ss << "RedisClient::command called with invalid state " + ss << "RedisAsyncClient::command called with invalid state " << pimpl->state; pimpl->errorHandler(ss.str()); @@ -338,7 +318,7 @@ void RedisClient::singleShotSubscribe(const std::string &channel, } -void RedisClient::publish(const std::string &channel, const std::string &msg, +void RedisAsyncClient::publish(const std::string &channel, const std::string &msg, const boost::function &handler) { assert( pimpl->state == RedisClientImpl::Connected ); @@ -353,20 +333,20 @@ void RedisClient::publish(const std::string &channel, const std::string &msg, items[1] = channel; items[2] = msg; - pimpl->post(boost::bind(&RedisClientImpl::doCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); } else { std::stringstream ss; - ss << "RedisClient::command called with invalid state " + ss << "RedisAsyncClient::command called with invalid state " << pimpl->state; pimpl->errorHandler(ss.str()); } } -bool RedisClient::stateValid() const +bool RedisAsyncClient::stateValid() const { assert( pimpl->state == RedisClientImpl::Connected ); @@ -374,7 +354,7 @@ bool RedisClient::stateValid() const { std::stringstream ss; - ss << "RedisClient::command called with invalid state " + ss << "RedisAsyncClient::command called with invalid state " << pimpl->state; pimpl->errorHandler(ss.str()); @@ -384,4 +364,4 @@ bool RedisClient::stateValid() const return true; } -#endif // REDISCLIENT_REDISCLIENT_CPP +#endif // REDISASYNCCLIENT_REDISASYNCCLIENT_CPP diff --git a/src/redisclient/impl/redisclientimpl.cpp b/src/redisclient/impl/redisclientimpl.cpp index 85275ba..7192ed4 100644 --- a/src/redisclient/impl/redisclientimpl.cpp +++ b/src/redisclient/impl/redisclientimpl.cpp @@ -30,8 +30,8 @@ void RedisClientImpl::close() { boost::system::error_code ignored_ec; + errorHandler = boost::bind(&RedisClientImpl::ignoreErrorHandler, _1); socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); - errorHandler = boost::bind(&RedisClientImpl::ignoreErrorHandler, shared_from_this(), _1); state = RedisClientImpl::Closed; } } @@ -129,11 +129,7 @@ void RedisClientImpl::asyncWrite(const boost::system::error_code &ec, const size return; } - assert( queue.empty() == false ); - - const QueueItem &item = queue.front(); - - handlers.push( item.handler ); + assert(queue.empty() == false); queue.pop(); if( queue.empty() == false ) @@ -162,10 +158,77 @@ void RedisClientImpl::handleAsyncConnect(const boost::system::error_code &ec, } } -void RedisClientImpl::doCommand(const std::vector &command, - const boost::function &handler) +RedisValue RedisClientImpl::doSyncCommand(const std::vector &command) +{ + assert( queue.empty() ); + + using boost::system::error_code; + static const char crlf[] = {'\r', '\n'}; + + // FIXME: тут нужен boost::asio::buffers? + std::vector buff; + + // FIXME почему тут приходится специализировать функцию? + append(buff, '*'); + append(buff, boost::lexical_cast(command.size())); + append<>(buff, crlf); + + std::vector::const_iterator it = command.begin(), end = command.end(); + for(; it != end; ++it) + { + append(buff, '$'); + append(buff, boost::lexical_cast(it->size())); + append<>(buff, crlf); + append(buff, boost::lexical_cast(*it)); + append<>(buff, crlf); + } + + boost::system::error_code ec; + boost::asio::write(socket, boost::asio::buffer(buff.data(), buff.size()), ec); + + if( ec ) + { + errorHandler(ec.message()); + return RedisValue(); + } + else + { + boost::array inbuff; + + for(;;) + { + size_t size = socket.read_some(boost::asio::buffer(inbuff)); + + for(size_t pos = 0; pos < size;) + { + std::pair result = + redisParser.parse(inbuff.data() + pos, size - pos); + + if( result.second == RedisParser::Completed ) + { + // FIXME тут требуется обработка для subscribe и unsubscribe + // doProcessMessage(redisParser.result()); + return redisParser.result(); + } + else if( result.second == RedisParser::Incompleted ) + { + continue; + } + else + { + errorHandler("[RedisClient] Parser error"); + return RedisValue(); + } + + pos += result.first; + } + } + } +} + +void RedisClientImpl::doAsyncCommand(const std::vector &command, + const boost::function &handler) { - using boost::system::error_code; static const char crlf[] = {'\r', '\n'}; @@ -189,6 +252,8 @@ void RedisClientImpl::doCommand(const std::vector &command, append(*item.buff.get(), crlf); } + handlers.push( item.handler ); + if( queue.size() == 1 ) { boost::asio::async_write(socket, @@ -259,7 +324,7 @@ void RedisClientImpl::append(std::vector &vec, const char *s) } template -void RedisClientImpl::append(std::vector &vec, const char s[size]) +void RedisClientImpl::append(std::vector &vec, const char (&s)[size]) { vec.insert(vec.end(), s, s + size); } diff --git a/src/redisclient/impl/redisclientimpl.h b/src/redisclient/impl/redisclientimpl.h index d0016f0..ed34770 100644 --- a/src/redisclient/impl/redisclientimpl.h +++ b/src/redisclient/impl/redisclientimpl.h @@ -18,7 +18,6 @@ #include #include -#include "../redisclient.h" #include "../redisparser.h" #include "../config.h" @@ -33,7 +32,9 @@ class RedisClientImpl : public boost::enable_shared_from_this { REDIS_CLIENT_DECL void close(); - REDIS_CLIENT_DECL void doCommand( + REDIS_CLIENT_DECL RedisValue doSyncCommand(const std::vector &command); + + REDIS_CLIENT_DECL void doAsyncCommand( const std::vector &command, const boost::function &handler); @@ -45,13 +46,13 @@ class RedisClientImpl : public boost::enable_shared_from_this { REDIS_CLIENT_DECL void onRedisError(const RedisValue &); REDIS_CLIENT_DECL void defaulErrorHandler(const std::string &s); - REDIS_CLIENT_DECL void ignoreErrorHandler(const std::string &s); + REDIS_CLIENT_DECL static void ignoreErrorHandler(const std::string &s); REDIS_CLIENT_DECL static void append(std::vector &vec, const std::string &s); REDIS_CLIENT_DECL static void append(std::vector &vec, const char *s); REDIS_CLIENT_DECL static void append(std::vector &vec, char c); template - REDIS_CLIENT_DECL static void append(std::vector &vec, const char s[size]); + REDIS_CLIENT_DECL static void append(std::vector &vec, const char (&s)[size]); template REDIS_CLIENT_DECL void post(const Handler &handler); diff --git a/src/redisclient/impl/redissyncclient.cpp b/src/redisclient/impl/redissyncclient.cpp new file mode 100644 index 0000000..0659e82 --- /dev/null +++ b/src/redisclient/impl/redissyncclient.cpp @@ -0,0 +1,255 @@ +/* + * Copyright (C) Alex Nekipelov (alex@nekipelov.net) + * License: MIT + */ + +#ifndef REDISCLIENT_REDISSYNCCLIENT_CPP +#define REDISCLIENT_REDISSYNCCLIENT_CPP + +#include +#include "../redissyncclient.h" + +RedisSyncClient::RedisSyncClient(boost::asio::io_service &ioService) + : pimpl(boost::make_shared(boost::ref(ioService))) +{ + pimpl->errorHandler = boost::bind(&RedisClientImpl::defaulErrorHandler, + pimpl, _1); +} + +RedisSyncClient::~RedisSyncClient() +{ + pimpl->close(); +} + +bool RedisSyncClient::connect(const boost::asio::ip::tcp::endpoint &endpoint, + std::string &errmsg) +{ + boost::system::error_code ec; + + pimpl->socket.connect(endpoint, ec); + + if( !ec ) + { + pimpl->state = RedisClientImpl::Connected; + pimpl->processMessage(); + return true; + } + else + { + errmsg = ec.message(); + return false; + } +} + +bool RedisSyncClient::connect(const boost::asio::ip::address &address, + unsigned short port, + std::string &errmsg) +{ + boost::asio::ip::tcp::endpoint endpoint(address, port); + + return connect(endpoint, errmsg); +} + +void RedisSyncClient::installErrorHandler( + const boost::function &handler) +{ + pimpl->errorHandler = handler; +} + +RedisValue RedisSyncClient::command(const std::string &s) +{ + if(stateValid()) + { + std::vector items(1); + items[0] = s; + + return pimpl->doSyncCommand(items); + } + else + { + return RedisValue(); + } +} + +RedisValue RedisSyncClient::command(const std::string &cmd, const RedisBuffer &arg1) +{ + if(stateValid()) + { + std::vector items(2); + items[0] = cmd; + items[1] = std::string(arg1.data(), arg1.data() + arg1.size()); + + return pimpl->doSyncCommand(items); + } + else + { + return RedisValue(); + } +} + +RedisValue RedisSyncClient::command(const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2) +{ + if(stateValid()) + { + std::vector items(3); + items[0] = cmd; + items[1] = std::string(arg1.data(), arg1.data() + arg1.size()); + items[2] = std::string(arg2.data(), arg2.data() + arg2.size()); + + return pimpl->doSyncCommand(items); + } + else + { + return RedisValue(); + } +} + +RedisValue RedisSyncClient::command(const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const RedisBuffer &arg3) +{ + if(stateValid()) + { + std::vector items(4); + items[0] = cmd; + items[1] = std::string(arg1.data(), arg1.data() + arg1.size()); + items[2] = std::string(arg2.data(), arg2.data() + arg2.size()); + items[3] = std::string(arg3.data(), arg3.data() + arg3.size()); + + return pimpl->doSyncCommand(items); + } + else + { + return RedisValue(); + } +} + +RedisValue RedisSyncClient::command(const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const RedisBuffer &arg3, + const RedisBuffer &arg4) +{ + if(stateValid()) + { + std::vector items(5); + items[0] = cmd; + items[1] = std::string(arg1.data(), arg1.data() + arg1.size()); + items[2] = std::string(arg2.data(), arg2.data() + arg2.size()); + items[3] = std::string(arg3.data(), arg3.data() + arg3.size()); + items[4] = std::string(arg4.data(), arg4.data() + arg4.size()); + + return pimpl->doSyncCommand(items); + } + else + { + return RedisValue(); + } +} + +RedisValue RedisSyncClient::command(const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const RedisBuffer &arg3, + const RedisBuffer &arg4, const RedisBuffer &arg5) +{ + if(stateValid()) + { + std::vector items(6); + items[0] = cmd; + items[1] = std::string(arg1.data(), arg1.data() + arg1.size()); + items[2] = std::string(arg2.data(), arg2.data() + arg2.size()); + items[3] = std::string(arg3.data(), arg3.data() + arg3.size()); + items[4] = std::string(arg4.data(), arg4.data() + arg4.size()); + items[5] = std::string(arg5.data(), arg5.data() + arg5.size()); + + return pimpl->doSyncCommand(items); + } + else + { + return RedisValue(); + } +} + +RedisValue RedisSyncClient::command(const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const RedisBuffer &arg3, + const RedisBuffer &arg4, const RedisBuffer &arg5, + const RedisBuffer &arg6) +{ + if(stateValid()) + { + std::vector items(7); + items[0] = cmd; + items[1] = std::string(arg1.data(), arg1.data() + arg1.size()); + items[2] = std::string(arg2.data(), arg2.data() + arg2.size()); + items[3] = std::string(arg3.data(), arg3.data() + arg3.size()); + items[4] = std::string(arg4.data(), arg4.data() + arg4.size()); + items[5] = std::string(arg5.data(), arg5.data() + arg5.size()); + items[6] = std::string(arg6.data(), arg6.data() + arg6.size()); + + return pimpl->doSyncCommand(items); + } + else + { + return RedisValue(); + } +} + +RedisValue RedisSyncClient::command(const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const RedisBuffer &arg3, + const RedisBuffer &arg4, const RedisBuffer &arg5, + const RedisBuffer &arg6, const RedisBuffer &arg7) +{ + if(stateValid()) + { + std::vector items(8); + items[0] = cmd; + items[1] = std::string(arg1.data(), arg1.data() + arg1.size()); + items[2] = std::string(arg2.data(), arg2.data() + arg2.size()); + items[3] = std::string(arg3.data(), arg3.data() + arg3.size()); + items[4] = std::string(arg4.data(), arg4.data() + arg4.size()); + items[5] = std::string(arg5.data(), arg5.data() + arg5.size()); + items[6] = std::string(arg6.data(), arg6.data() + arg6.size()); + items[7] = std::string(arg7.data(), arg7.data() + arg7.size()); + + return pimpl->doSyncCommand(items); + } + else + { + return RedisValue(); + } +} + +RedisValue RedisSyncClient::command(const std::string &cmd, const std::list &args) +{ + if(stateValid()) + { + std::vector items(1); + items[0] = cmd; + + items.reserve(1 + args.size()); + + std::copy(args.begin(), args.end(), std::back_inserter(items)); + return pimpl->doSyncCommand(items); + } + else + { + return RedisValue(); + } +} + +bool RedisSyncClient::stateValid() const +{ + assert( pimpl->state == RedisClientImpl::Connected ); + + if( pimpl->state != RedisClientImpl::Connected ) + { + std::stringstream ss; + + ss << "RedisClient::command called with invalid state " + << pimpl->state; + + pimpl->errorHandler(ss.str()); + return false; + } + + return true; +} + +#endif // REDISCLIENT_REDISSYNCCLIENT_CPP diff --git a/src/redisclient/redisasyncclient.h b/src/redisclient/redisasyncclient.h new file mode 100644 index 0000000..7fd4361 --- /dev/null +++ b/src/redisclient/redisasyncclient.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) Alex Nekipelov (alex@nekipelov.net) + * License: MIT + */ + +#ifndef REDISASYNCCLIENT_REDISCLIENT_H +#define REDISASYNCCLIENT_REDISCLIENT_H + +#include +#include +#include + +#include +#include + +#include "impl/redisclientimpl.h" +#include "redisvalue.h" +#include "config.h" + +class RedisClientImpl; + +class RedisAsyncClient : boost::noncopyable { +public: + // Subscribe handle. + struct Handle { + size_t id; + std::string channel; + }; + + REDIS_CLIENT_DECL RedisAsyncClient(boost::asio::io_service &ioService); + REDIS_CLIENT_DECL ~RedisAsyncClient(); + + // Connect to redis server + REDIS_CLIENT_DECL void connect( + const boost::asio::ip::address &address, + unsigned short port, + const boost::function &handler); + + // Connect to redis server + REDIS_CLIENT_DECL void connect( + const boost::asio::ip::tcp::endpoint &endpoint, + const boost::function &handler); + + // backward compatibility + inline void asyncConnect( + const boost::asio::ip::address &address, + unsigned short port, + const boost::function &handler) + { + connect(address, port, handler); + } + + // backward compatibility + inline void asyncConnect( + const boost::asio::ip::tcp::endpoint &endpoint, + const boost::function &handler) + { + connect(endpoint, handler); + } + + + // Set custom error handler. + REDIS_CLIENT_DECL void installErrorHandler( + const boost::function &handler); + + // Execute command on Redis server. + REDIS_CLIENT_DECL void command( + const std::string &cmd, + const boost::function &handler = &dummyHandler); + + // Execute command on Redis server with one argument. + REDIS_CLIENT_DECL void command( + const std::string &cmd, const std::string &arg1, + const boost::function &handler = &dummyHandler); + + // Execute command on Redis server with two arguments. + REDIS_CLIENT_DECL void command( + const std::string &cmd, const std::string &arg1, const std::string &arg2, + const boost::function &handler = &dummyHandler); + + // Execute command on Redis server with three arguments. + REDIS_CLIENT_DECL void command( + const std::string &cmd, const std::string &arg1, + const std::string &arg2, const std::string &arg3, + const boost::function &handler = &dummyHandler); + + // Execute command on Redis server with four arguments. + REDIS_CLIENT_DECL void command( + const std::string &cmd, const std::string &arg1, const std::string &arg2, + const std::string &arg3, const std::string &arg4, + const boost::function &handler = &dummyHandler); + + // Execute command on Redis server with five arguments. + REDIS_CLIENT_DECL void command( + const std::string &cmd, const std::string &arg1, + const std::string &arg2, const std::string &arg3, + const std::string &arg4, const std::string &arg5, + const boost::function &handler = &dummyHandler); + + // Execute command on Redis server with six arguments. + REDIS_CLIENT_DECL void command( + const std::string &cmd, const std::string &arg1, + const std::string &arg2, const std::string &arg3, + const std::string &arg4, const std::string &arg5, + const std::string &arg6, + const boost::function &handler = &dummyHandler); + + + // Execute command on Redis server with seven arguments. + REDIS_CLIENT_DECL void command( + const std::string &cmd, const std::string &arg1, + const std::string &arg2, const std::string &arg3, + const std::string &arg4, const std::string &arg5, + const std::string &arg6, const std::string &arg7, + const boost::function &handler = &dummyHandler); + + // Execute command on Redis server with the list of arguments. + REDIS_CLIENT_DECL void command( + const std::string &cmd, const std::list &args, + const boost::function &handler = &dummyHandler); + + // Subscribe to channel. Handler msgHandler will be called + // when someone publish message on channel. Call unsubscribe + // to stop the subscription. + REDIS_CLIENT_DECL Handle subscribe( + const std::string &channelName, + const boost::function &msgHandler, + const boost::function &handler = &dummyHandler); + + // Unsubscribe + REDIS_CLIENT_DECL void unsubscribe(const Handle &handle); + + // Subscribe to channel. Handler msgHandler will be called + // when someone publish message on channel; it will be + // unsubscribed after call. + REDIS_CLIENT_DECL void singleShotSubscribe( + const std::string &channel, + const boost::function &msgHandler, + const boost::function &handler = &dummyHandler); + + // Publish message on channel. + REDIS_CLIENT_DECL void publish( + const std::string &channel, const std::string &msg, + const boost::function &handler = &dummyHandler); + + REDIS_CLIENT_DECL static void dummyHandler(const RedisValue &) {} + +protected: + REDIS_CLIENT_DECL bool stateValid() const; + +private: + boost::shared_ptr pimpl; +}; + +#ifdef REDIS_CLIENT_HEADER_ONLY +#include "impl/redisasyncclient.cpp" +#endif + +#endif // REDISASYNCCLIENT_REDISCLIENT_H diff --git a/src/redisclient/redisbuffer.h b/src/redisclient/redisbuffer.h new file mode 100644 index 0000000..eb78138 --- /dev/null +++ b/src/redisclient/redisbuffer.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) Alex Nekipelov (alex@nekipelov.net) + * License: MIT + */ + + +#ifndef REDISSYNCCLIENT_REDISBUFFER_H +#define REDISSYNCCLIENT_REDISBUFFER_H + +#include + +#include +#include + +#include "config.h" + +class RedisBuffer : boost::noncopyable { +public: + inline RedisBuffer(const char *ptr, size_t size); + inline RedisBuffer(const char *s); + inline RedisBuffer(const std::string &s); + inline RedisBuffer(const std::vector &buf); + + inline size_t size() const; + inline const char *data() const; + +private: + const char *ptr_; + const size_t size_; +}; + + +RedisBuffer::RedisBuffer(const char *ptr, size_t size) + : ptr_(ptr), size_(size) +{ +} + +RedisBuffer::RedisBuffer(const char *s) + : ptr_(s), size_(s == NULL ? 0 : strlen(s)) +{ +} + +RedisBuffer::RedisBuffer(const std::string &s) + : ptr_(s.c_str()), size_(s.length()) +{ +} + +RedisBuffer::RedisBuffer(const std::vector &buf) + : ptr_(buf.empty() ? NULL : &buf[0]), size_(buf.size()) +{ +} + +size_t RedisBuffer::size() const +{ + return size_; +} + +const char *RedisBuffer::data() const +{ + return ptr_; +} + +#endif //REDISSYNCCLIENT_REDISBUFFER_H + diff --git a/src/redisclient/redisclient.h b/src/redisclient/redisclient.h index ef8d265..a6c26d1 100644 --- a/src/redisclient/redisclient.h +++ b/src/redisclient/redisclient.h @@ -6,140 +6,9 @@ #ifndef REDISCLIENT_REDISCLIENT_H #define REDISCLIENT_REDISCLIENT_H -#include -#include -#include +#include "redisasyncclient.h" -#include -#include - -#include "impl/redisclientimpl.h" -#include "redisvalue.h" -#include "config.h" - -class RedisClientImpl; - -class RedisClient : boost::noncopyable { -public: - // Subscribe handle. - struct Handle { - size_t id; - std::string channel; - }; - - REDIS_CLIENT_DECL RedisClient(boost::asio::io_service &ioService); - REDIS_CLIENT_DECL ~RedisClient(); - - // Connect to redis server, blocking call. - REDIS_CLIENT_DECL bool connect(const boost::asio::ip::address &address, - unsigned short port); - - // Connect to redis server, asynchronous call. - REDIS_CLIENT_DECL void asyncConnect( - const boost::asio::ip::address &address, - unsigned short port, - const boost::function &handler); - - // Connect to redis server, asynchronous call. - REDIS_CLIENT_DECL void asyncConnect( - const boost::asio::ip::tcp::endpoint &endpoint, - const boost::function &handler); - - // Set custom error handler. - REDIS_CLIENT_DECL void installErrorHandler( - const boost::function &handler); - - // Execute command on Redis server. - REDIS_CLIENT_DECL void command( - const std::string &cmd, - const boost::function &handler = &dummyHandler); - - // Execute command on Redis server with one argument. - REDIS_CLIENT_DECL void command( - const std::string &cmd, const std::string &arg1, - const boost::function &handler = &dummyHandler); - - // Execute command on Redis server with two arguments. - REDIS_CLIENT_DECL void command( - const std::string &cmd, const std::string &arg1, const std::string &arg2, - const boost::function &handler = &dummyHandler); - - // Execute command on Redis server with three arguments. - REDIS_CLIENT_DECL void command( - const std::string &cmd, const std::string &arg1, - const std::string &arg2, const std::string &arg3, - const boost::function &handler = &dummyHandler); - - // Execute command on Redis server with four arguments. - REDIS_CLIENT_DECL void command( - const std::string &cmd, const std::string &arg1, const std::string &arg2, - const std::string &arg3, const std::string &arg4, - const boost::function &handler = &dummyHandler); - - // Execute command on Redis server with five arguments. - REDIS_CLIENT_DECL void command( - const std::string &cmd, const std::string &arg1, - const std::string &arg2, const std::string &arg3, - const std::string &arg4, const std::string &arg5, - const boost::function &handler = &dummyHandler); - - // Execute command on Redis server with six arguments. - REDIS_CLIENT_DECL void command( - const std::string &cmd, const std::string &arg1, - const std::string &arg2, const std::string &arg3, - const std::string &arg4, const std::string &arg5, - const std::string &arg6, - const boost::function &handler = &dummyHandler); - - - // Execute command on Redis server with seven arguments. - REDIS_CLIENT_DECL void command( - const std::string &cmd, const std::string &arg1, - const std::string &arg2, const std::string &arg3, - const std::string &arg4, const std::string &arg5, - const std::string &arg6, const std::string &arg7, - const boost::function &handler = &dummyHandler); - - // Execute command on Redis server with the list of arguments. - REDIS_CLIENT_DECL void command( - const std::string &cmd, const std::list &args, - const boost::function &handler = &dummyHandler); - - // Subscribe to channel. Handler msgHandler will be called - // when someone publish message on channel. Call unsubscribe - // to stop the subscription. - REDIS_CLIENT_DECL Handle subscribe( - const std::string &channelName, - const boost::function &msgHandler, - const boost::function &handler = &dummyHandler); - - // Unsubscribe - REDIS_CLIENT_DECL void unsubscribe(const Handle &handle); - - // Subscribe to channel. Handler msgHandler will be called - // when someone publish message on channel; it will be - // unsubscribed after call. - REDIS_CLIENT_DECL void singleShotSubscribe( - const std::string &channel, - const boost::function &msgHandler, - const boost::function &handler = &dummyHandler); - - // Publish message on channel. - REDIS_CLIENT_DECL void publish( - const std::string &channel, const std::string &msg, - const boost::function &handler = &dummyHandler); - - REDIS_CLIENT_DECL static void dummyHandler(const RedisValue &) {} - -protected: - REDIS_CLIENT_DECL bool stateValid() const; - -private: - boost::shared_ptr pimpl; -}; - -#ifdef REDIS_CLIENT_HEADER_ONLY -#include "impl/redisclient.cpp" -#endif +// backward compatibility +typedef RedisAsyncClient RedisClient; #endif // REDISCLIENT_REDISCLIENT_H diff --git a/src/redisclient/redissyncclient.h b/src/redisclient/redissyncclient.h new file mode 100644 index 0000000..7d446a3 --- /dev/null +++ b/src/redisclient/redissyncclient.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) Alex Nekipelov (alex@nekipelov.net) + * License: MIT + */ + +#ifndef REDISSYNCCLIENT_REDISCLIENT_H +#define REDISSYNCCLIENT_REDISCLIENT_H + +#include +#include +#include + +#include +#include + +#include "impl/redisclientimpl.h" +#include "redisbuffer.h" +#include "redisvalue.h" +#include "config.h" + +class RedisClientImpl; + +class RedisSyncClient : boost::noncopyable { +public: + REDIS_CLIENT_DECL RedisSyncClient(boost::asio::io_service &ioService); + REDIS_CLIENT_DECL ~RedisSyncClient(); + + // Connect to redis server + REDIS_CLIENT_DECL bool connect( + const boost::asio::ip::tcp::endpoint &endpoint, + std::string &errmsg); + + // Connect to redis server + REDIS_CLIENT_DECL bool connect( + const boost::asio::ip::address &address, + unsigned short port, + std::string &errmsg); + + // Set custom error handler. + REDIS_CLIENT_DECL void installErrorHandler( + const boost::function &handler); + + // Execute command on Redis server. + REDIS_CLIENT_DECL RedisValue command(const std::string &cmd); + + // Execute command on Redis server with one argument. + REDIS_CLIENT_DECL RedisValue command(const std::string &cmd, const RedisBuffer &arg1); + + // Execute command on Redis server with two arguments. + REDIS_CLIENT_DECL RedisValue command( + const std::string &cmd, const RedisBuffer &arg1, const RedisBuffer &arg2); + + // Execute command on Redis server with three arguments. + REDIS_CLIENT_DECL RedisValue command( + const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const RedisBuffer &arg3); + + // Execute command on Redis server with four arguments. + REDIS_CLIENT_DECL RedisValue command( + const std::string &cmd, const RedisBuffer &arg1, const RedisBuffer &arg2, + const RedisBuffer &arg3, const RedisBuffer &arg4); + + // Execute command on Redis server with five arguments. + REDIS_CLIENT_DECL RedisValue command( + const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const RedisBuffer &arg3, + const RedisBuffer &arg4, const RedisBuffer &arg5); + + // Execute command on Redis server with six arguments. + REDIS_CLIENT_DECL RedisValue command( + const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const RedisBuffer &arg3, + const RedisBuffer &arg4, const RedisBuffer &arg5, + const RedisBuffer &arg6); + + // Execute command on Redis server with seven arguments. + REDIS_CLIENT_DECL RedisValue command( + const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const RedisBuffer &arg3, + const RedisBuffer &arg4, const RedisBuffer &arg5, + const RedisBuffer &arg6, const RedisBuffer &arg7); + + // Execute command on Redis server with the list of arguments. + REDIS_CLIENT_DECL RedisValue command( + const std::string &cmd, const std::list &args); + +protected: + REDIS_CLIENT_DECL bool stateValid() const; + +private: + boost::shared_ptr pimpl; +}; + +#ifdef REDIS_CLIENT_HEADER_ONLY +#include "impl/redissyncclient.cpp" +#endif + +#endif // REDISSYNCCLIENT_REDISCLIENT_H diff --git a/src/redisclient/version.h b/src/redisclient/version.h index 63488b9..bd692d0 100644 --- a/src/redisclient/version.h +++ b/src/redisclient/version.h @@ -6,6 +6,6 @@ #ifndef REDISCLIENT_VERSION_H #define REDISCLIENT_VERSION_H -#define REDIS_CLIENT_VERSION 302 // 0.3.2 +#define REDIS_CLIENT_VERSION 400 // 0.4.0 #endif // REDISCLIENT_VERSION_H From a4e325df7fa1efcf472a0bacbc1f04f3eaad1d86 Mon Sep 17 00:00:00 2001 From: Alex Nekipelov Date: Fri, 30 Jan 2015 17:34:56 +0300 Subject: [PATCH 02/21] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6480e2d..7356f11 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ redisclient =========== -Build status: [![Build Status](https://travis-ci.org/nekipelov/redisclient.svg?branch=master)](https://travis-ci.org/nekipelov/redisclient) +Build status: [![Build Status](https://travis-ci.org/nekipelov/redisclient.svg?branch=unstable)](https://travis-ci.org/nekipelov/redisclient) Current version: 0.4.0 From cfae0db49240f90f41f395197d3431a8ed5bccee Mon Sep 17 00:00:00 2001 From: Alex Nekipelov Date: Wed, 25 Mar 2015 20:07:49 +0300 Subject: [PATCH 03/21] Support for binary arguments --- examples/async_pubsub.cpp | 4 +- examples/sync_set_get.cpp | 12 +-- src/redisclient/impl/redisasyncclient.cpp | 119 ++++++++++++---------- src/redisclient/impl/redisclientimpl.cpp | 73 ++++++------- src/redisclient/impl/redisclientimpl.h | 12 ++- src/redisclient/impl/redisparser.cpp | 46 +++++---- src/redisclient/impl/redissyncclient.cpp | 74 +++++++------- src/redisclient/impl/redisvalue.cpp | 24 ++++- src/redisclient/redisasyncclient.h | 43 ++++---- src/redisclient/redisbuffer.h | 11 +- src/redisclient/redisparser.h | 3 +- src/redisclient/redisvalue.h | 15 ++- 12 files changed, 243 insertions(+), 193 deletions(-) diff --git a/examples/async_pubsub.cpp b/examples/async_pubsub.cpp index 7123716..957aa37 100644 --- a/examples/async_pubsub.cpp +++ b/examples/async_pubsub.cpp @@ -7,8 +7,10 @@ static const std::string channelName = "unique-redis-channel-name-example"; -void subscribeHandler(boost::asio::io_service &ioService, const std::string &msg) +void subscribeHandler(boost::asio::io_service &ioService, const std::vector &buf) { + std::string msg(buf.begin(), buf.end()); + std::cerr << "Message: " << msg << std::endl; if( msg == "stop" ) diff --git a/examples/sync_set_get.cpp b/examples/sync_set_get.cpp index a896ae6..1b8e00a 100644 --- a/examples/sync_set_get.cpp +++ b/examples/sync_set_get.cpp @@ -22,14 +22,14 @@ int main(int, char **) const std::string key = "unique-redis-key-example"; const char rawValue [] = "unique-redis-value"; - const std::string stringValue(rawValue, rawValue + sizeof(rawValue)); - const std::vector vectorValue(rawValue, rawValue + sizeof(rawValue)); + const std::string stringValue(rawValue, rawValue + sizeof(rawValue) - 1); + const std::vector vectorValue(rawValue, rawValue + sizeof(rawValue) - 1); { // raw redis.command("SET", key, rawValue); RedisValue value = redis.command("GET", key); - + if( value.toString() != rawValue ) { std::cerr << "Invalid value from redis: " << value.toString() << std::endl; @@ -53,14 +53,14 @@ int main(int, char **) // vector redis.command("SET", key, vectorValue); RedisValue value = redis.command("GET", key); - /* - if( value.toString() != vectorValue ) + + if( value.toByteArray() != vectorValue ) { std::cerr << "Invalid value from redis: " << value.toString() << std::endl; return EXIT_FAILURE; } - * */ } + return EXIT_SUCCESS; } diff --git a/src/redisclient/impl/redisasyncclient.cpp b/src/redisclient/impl/redisasyncclient.cpp index 06ee8e6..7fd8e12 100644 --- a/src/redisclient/impl/redisasyncclient.cpp +++ b/src/redisclient/impl/redisasyncclient.cpp @@ -47,83 +47,88 @@ void RedisAsyncClient::command(const std::string &s, const boost::function items(1); + std::vector items(1); items[0] = s; - pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, + pimpl->makeCommand(items), handler)); } } -void RedisAsyncClient::command(const std::string &cmd, const std::string &arg1, +void RedisAsyncClient::command(const std::string &cmd, const RedisBuffer &arg1, const boost::function &handler) { if(stateValid()) { - std::vector items(2); + std::vector items(2); items[0] = cmd; items[1] = arg1; - pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, + pimpl->makeCommand(items), handler)); } } -void RedisAsyncClient::command(const std::string &cmd, const std::string &arg1, - const std::string &arg2, +void RedisAsyncClient::command(const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const boost::function &handler) { if(stateValid()) { - std::vector items(3); + std::vector items(3); items[0] = cmd; items[1] = arg1; items[2] = arg2; - pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, + pimpl->makeCommand(items), handler)); } } -void RedisAsyncClient::command(const std::string &cmd, const std::string &arg1, - const std::string &arg2, const std::string &arg3, +void RedisAsyncClient::command(const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const RedisBuffer &arg3, const boost::function &handler) { if(stateValid()) { - std::vector items(4); + std::vector items(4); items[0] = cmd; items[1] = arg1; items[2] = arg2; items[3] = arg3; - pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, + pimpl->makeCommand(items), handler)); } } -void RedisAsyncClient::command(const std::string &cmd, const std::string &arg1, - const std::string &arg2, const std::string &arg3, - const std::string &arg4, +void RedisAsyncClient::command(const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const RedisBuffer &arg3, + const RedisBuffer &arg4, const boost::function &handler) { if(stateValid()) { - std::vector items(5); + std::vector items(5); items[0] = cmd; items[1] = arg1; items[2] = arg2; items[3] = arg3; items[4] = arg4; - pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, + pimpl->makeCommand(items), handler)); } } -void RedisAsyncClient::command(const std::string &cmd, const std::string &arg1, - const std::string &arg2, const std::string &arg3, - const std::string &arg4, const std::string &arg5, +void RedisAsyncClient::command(const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const RedisBuffer &arg3, + const RedisBuffer &arg4, const RedisBuffer &arg5, const boost::function &handler) { if(stateValid()) { - std::vector items(6); + std::vector items(6); items[0] = cmd; items[1] = arg1; items[2] = arg2; @@ -131,19 +136,20 @@ void RedisAsyncClient::command(const std::string &cmd, const std::string &arg1, items[4] = arg4; items[5] = arg5; - pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, + pimpl->makeCommand(items), handler)); } } -void RedisAsyncClient::command(const std::string &cmd, const std::string &arg1, - const std::string &arg2, const std::string &arg3, - const std::string &arg4, const std::string &arg5, - const std::string &arg6, +void RedisAsyncClient::command(const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const RedisBuffer &arg3, + const RedisBuffer &arg4, const RedisBuffer &arg5, + const RedisBuffer &arg6, const boost::function &handler) { if(stateValid()) { - std::vector items(7); + std::vector items(7); items[0] = cmd; items[1] = arg1; items[2] = arg2; @@ -152,19 +158,20 @@ void RedisAsyncClient::command(const std::string &cmd, const std::string &arg1, items[5] = arg5; items[6] = arg6; - pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, + pimpl->makeCommand(items), handler)); } } -void RedisAsyncClient::command(const std::string &cmd, const std::string &arg1, - const std::string &arg2, const std::string &arg3, - const std::string &arg4, const std::string &arg5, - const std::string &arg6, const std::string &arg7, +void RedisAsyncClient::command(const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const RedisBuffer &arg3, + const RedisBuffer &arg4, const RedisBuffer &arg5, + const RedisBuffer &arg6, const RedisBuffer &arg7, const boost::function &handler) { if(stateValid()) { - std::vector items(8); + std::vector items(8); items[0] = cmd; items[1] = arg1; items[2] = arg2; @@ -174,44 +181,47 @@ void RedisAsyncClient::command(const std::string &cmd, const std::string &arg1, items[6] = arg6; items[7] = arg7; - pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, + pimpl->makeCommand(items), handler)); } } -void RedisAsyncClient::command(const std::string &cmd, const std::list &args, +void RedisAsyncClient::command(const std::string &cmd, const std::list &args, const boost::function &handler) { if(stateValid()) { - std::vector items(1); + std::vector items(1); items[0] = cmd; items.reserve(1 + args.size()); std::copy(args.begin(), args.end(), std::back_inserter(items)); - pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, + pimpl->makeCommand(items), handler)); } } RedisAsyncClient::Handle RedisAsyncClient::subscribe( const std::string &channel, - const boost::function &msgHandler, + const boost::function &msg)> &msgHandler, const boost::function &handler) { assert( pimpl->state == RedisClientImpl::Connected || pimpl->state == RedisClientImpl::Subscribed); - static std::string subscribe = "SUBSCRIBE"; + static const std::string subscribe = "SUBSCRIBE"; if( pimpl->state == RedisClientImpl::Connected || pimpl->state == RedisClientImpl::Subscribed ) { Handle handle = {pimpl->subscribeSeq++, channel}; - std::vector items(2); + std::vector items(2); items[0] = subscribe; items[1] = channel; - pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, + pimpl->makeCommand(items), handler)); pimpl->msgHandlers.insert(std::make_pair(channel, std::make_pair(handle.id, msgHandler))); pimpl->state = RedisClientImpl::Subscribed; @@ -239,7 +249,7 @@ void RedisAsyncClient::unsubscribe(const Handle &handle) assert( pimpl->state == RedisClientImpl::Connected || pimpl->state == RedisClientImpl::Subscribed); - static std::string unsubscribe = "UNSUBSCRIBE"; + static const std::string unsubscribe = "UNSUBSCRIBE"; if( pimpl->state == RedisClientImpl::Connected || pimpl->state == RedisClientImpl::Subscribed ) @@ -260,12 +270,13 @@ void RedisAsyncClient::unsubscribe(const Handle &handle) } } - std::vector items(2); + std::vector items(2); items[0] = unsubscribe; items[1] = handle.channel; // Unsubscribe command for Redis - pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, dummyHandler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, + pimpl->makeCommand(items), dummyHandler)); } else { @@ -287,22 +298,23 @@ void RedisAsyncClient::unsubscribe(const Handle &handle) } void RedisAsyncClient::singleShotSubscribe(const std::string &channel, - const boost::function &msgHandler, + const boost::function &msg)> &msgHandler, const boost::function &handler) { assert( pimpl->state == RedisClientImpl::Connected || pimpl->state == RedisClientImpl::Subscribed); - static std::string subscribe = "SUBSCRIBE"; + static const std::string subscribe = "SUBSCRIBE"; if( pimpl->state == RedisClientImpl::Connected || pimpl->state == RedisClientImpl::Subscribed ) { - std::vector items(2); + std::vector items(2); items[0] = subscribe; items[1] = channel; - pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, + pimpl->makeCommand(items), handler)); pimpl->singleShotMsgHandlers.insert(std::make_pair(channel, msgHandler)); pimpl->state = RedisClientImpl::Subscribed; } @@ -318,22 +330,23 @@ void RedisAsyncClient::singleShotSubscribe(const std::string &channel, } -void RedisAsyncClient::publish(const std::string &channel, const std::string &msg, +void RedisAsyncClient::publish(const std::string &channel, const RedisBuffer &msg, const boost::function &handler) { assert( pimpl->state == RedisClientImpl::Connected ); - static std::string publish = "PUBLISH"; + static const std::string publish = "PUBLISH"; if( pimpl->state == RedisClientImpl::Connected ) { - std::vector items(3); + std::vector items(3); items[0] = publish; items[1] = channel; items[2] = msg; - pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, items, handler)); + pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, + pimpl->makeCommand(items), handler)); } else { diff --git a/src/redisclient/impl/redisclientimpl.cpp b/src/redisclient/impl/redisclientimpl.cpp index 7192ed4..8279426 100644 --- a/src/redisclient/impl/redisclientimpl.cpp +++ b/src/redisclient/impl/redisclientimpl.cpp @@ -65,14 +65,14 @@ void RedisClientImpl::doProcessMessage(const RedisValue &v) SingleShotHandlersMap::iterator it = singleShotMsgHandlers.find(queue.toString()); if( it != singleShotMsgHandlers.end() ) { - strand.post(boost::bind(it->second, value.toString())); + strand.post(boost::bind(it->second, value.toByteArray())); singleShotMsgHandlers.erase(it); } std::pair pair = msgHandlers.equal_range(queue.toString()); for(MsgHandlersMap::iterator it = pair.first; it != pair.second; ++it) - strand.post(boost::bind(it->second.second, value.toString())); + strand.post(boost::bind(it->second.second, value.toByteArray())); } else if( cmd == "subscribe" && handlers.empty() == false ) { @@ -158,33 +158,40 @@ void RedisClientImpl::handleAsyncConnect(const boost::system::error_code &ec, } } -RedisValue RedisClientImpl::doSyncCommand(const std::vector &command) +std::vector RedisClientImpl::makeCommand(const std::vector &items) { - assert( queue.empty() ); - - using boost::system::error_code; static const char crlf[] = {'\r', '\n'}; - // FIXME: тут нужен boost::asio::buffers? - std::vector buff; + std::vector result; - // FIXME почему тут приходится специализировать функцию? - append(buff, '*'); - append(buff, boost::lexical_cast(command.size())); - append<>(buff, crlf); + append(result, '*'); + append(result, boost::lexical_cast(items.size())); + append<>(result, crlf); - std::vector::const_iterator it = command.begin(), end = command.end(); + std::vector::const_iterator it = items.begin(), end = items.end(); for(; it != end; ++it) { - append(buff, '$'); - append(buff, boost::lexical_cast(it->size())); - append<>(buff, crlf); - append(buff, boost::lexical_cast(*it)); - append<>(buff, crlf); + append(result, '$'); + append(result, boost::lexical_cast(it->size())); + append<>(result, crlf); + append(result, *it); + append<>(result, crlf); } + return result; +} + +RedisValue RedisClientImpl::doSyncCommand(const std::vector &buff) +{ + assert( queue.empty() ); + boost::system::error_code ec; - boost::asio::write(socket, boost::asio::buffer(buff.data(), buff.size()), ec); + + + { + std::vector data = makeCommand(buff); + boost::asio::write(socket, boost::asio::buffer(data), ec); + } if( ec ) { @@ -206,8 +213,6 @@ RedisValue RedisClientImpl::doSyncCommand(const std::vector &comman if( result.second == RedisParser::Completed ) { - // FIXME тут требуется обработка для subscribe и unsubscribe - // doProcessMessage(redisParser.result()); return redisParser.result(); } else if( result.second == RedisParser::Incompleted ) @@ -226,32 +231,15 @@ RedisValue RedisClientImpl::doSyncCommand(const std::vector &comman } } -void RedisClientImpl::doAsyncCommand(const std::vector &command, +void RedisClientImpl::doAsyncCommand(const std::vector &buff, const boost::function &handler) { - using boost::system::error_code; - static const char crlf[] = {'\r', '\n'}; - QueueItem item; - item.buff.reset( new std::vector() ); + item.buff.reset( new std::vector(buff) ); item.handler = handler; queue.push(item); - append(*item.buff.get(), '*'); - append(*item.buff.get(), boost::lexical_cast(command.size())); - append(*item.buff.get(), crlf); - - std::vector::const_iterator it = command.begin(), end = command.end(); - for(; it != end; ++it) - { - append(*item.buff.get(), '$'); - append(*item.buff.get(), boost::lexical_cast(it->size())); - append(*item.buff.get(), crlf); - append(*item.buff.get(), boost::lexical_cast(*it)); - append(*item.buff.get(), crlf); - } - handlers.push( item.handler ); if( queue.size() == 1 ) @@ -313,6 +301,11 @@ void RedisClientImpl::ignoreErrorHandler(const std::string &) // empty } +void RedisClientImpl::append(std::vector &vec, const RedisBuffer &buf) +{ + vec.insert(vec.end(), buf.data(), buf.data() + buf.size()); +} + void RedisClientImpl::append(std::vector &vec, const std::string &s) { vec.insert(vec.end(), s.begin(), s.end()); diff --git a/src/redisclient/impl/redisclientimpl.h b/src/redisclient/impl/redisclientimpl.h index ed34770..e6feeff 100644 --- a/src/redisclient/impl/redisclientimpl.h +++ b/src/redisclient/impl/redisclientimpl.h @@ -19,6 +19,7 @@ #include #include "../redisparser.h" +#include "../redisbuffer.h" #include "../config.h" class RedisClientImpl : public boost::enable_shared_from_this { @@ -32,10 +33,12 @@ class RedisClientImpl : public boost::enable_shared_from_this { REDIS_CLIENT_DECL void close(); - REDIS_CLIENT_DECL RedisValue doSyncCommand(const std::vector &command); + REDIS_CLIENT_DECL static std::vector makeCommand(const std::vector &items); + + REDIS_CLIENT_DECL RedisValue doSyncCommand(const std::vector &buff); REDIS_CLIENT_DECL void doAsyncCommand( - const std::vector &command, + const std::vector &buff, const boost::function &handler); REDIS_CLIENT_DECL void sendNextCommand(); @@ -48,6 +51,7 @@ class RedisClientImpl : public boost::enable_shared_from_this { REDIS_CLIENT_DECL void defaulErrorHandler(const std::string &s); REDIS_CLIENT_DECL static void ignoreErrorHandler(const std::string &s); + REDIS_CLIENT_DECL static void append(std::vector &vec, const RedisBuffer &buf); REDIS_CLIENT_DECL static void append(std::vector &vec, const std::string &s); REDIS_CLIENT_DECL static void append(std::vector &vec, const char *s); REDIS_CLIENT_DECL static void append(std::vector &vec, char c); @@ -70,8 +74,8 @@ class RedisClientImpl : public boost::enable_shared_from_this { boost::array buf; size_t subscribeSeq; - typedef std::pair > MsgHandlerType; - typedef boost::function SingleShotHandlerType; + typedef std::pair &buf)> > MsgHandlerType; + typedef boost::function &buf)> SingleShotHandlerType; typedef std::multimap MsgHandlersMap; typedef std::multimap SingleShotHandlersMap; diff --git a/src/redisclient/impl/redisparser.cpp b/src/redisclient/impl/redisparser.cpp index 18fce17..11b5cc9 100644 --- a/src/redisclient/impl/redisparser.cpp +++ b/src/redisclient/impl/redisparser.cpp @@ -117,7 +117,7 @@ std::pair RedisParser::parseChunk(const char * switch(state) { case Start: - string.clear(); + buf.clear(); switch(c) { case stringReply: @@ -148,7 +148,7 @@ std::pair RedisParser::parseChunk(const char * } else if( isChar(c) && !isControl(c) ) { - string += c; + buf.push_back(c); } else { @@ -163,7 +163,7 @@ std::pair RedisParser::parseChunk(const char * } else if( isChar(c) && !isControl(c) ) { - string += c; + buf.push_back(c); } else { @@ -174,7 +174,7 @@ std::pair RedisParser::parseChunk(const char * case BulkSize: if( c == '\r' ) { - if( string.empty() ) + if( buf.empty() ) { state = Start; return std::make_pair(i + 1, Error); @@ -186,7 +186,7 @@ std::pair RedisParser::parseChunk(const char * } else if( isdigit(c) || c == '-' ) { - string += c; + buf.push_back(c); } else { @@ -199,7 +199,7 @@ std::pair RedisParser::parseChunk(const char * if( c == '\n') { state = Start; - valueStack.push(string); + valueStack.push(buf); return std::make_pair(i + 1, Completed); } else @@ -211,8 +211,10 @@ std::pair RedisParser::parseChunk(const char * case BulkSizeLF: if( c == '\n' ) { - bulkSize = strtol(string.c_str(), 0, 10); - string.clear(); + // TODO optimize me + std::string tmp(buf.begin(), buf.end()); + bulkSize = strtol(tmp.c_str(), 0, 10); + buf.clear(); if( bulkSize == -1 ) { @@ -231,14 +233,14 @@ std::pair RedisParser::parseChunk(const char * } else { - string.reserve(bulkSize); + buf.reserve(bulkSize); long int available = size - i - 1; long int canRead = std::min(bulkSize, available); if( canRead > 0 ) { - string.assign(ptr + i + 1, ptr + i + canRead + 1); + buf.assign(ptr + i + 1, ptr + i + canRead + 1); } i += canRead; @@ -267,7 +269,7 @@ std::pair RedisParser::parseChunk(const char * long int available = size - i; long int canRead = std::min(available, bulkSize); - string.insert(string.end(), ptr + i, ptr + canRead); + buf.insert(buf.end(), ptr + i, ptr + canRead); bulkSize -= canRead; i += canRead - 1; @@ -301,7 +303,7 @@ std::pair RedisParser::parseChunk(const char * if( c == '\n') { state = Start; - valueStack.push(string); + valueStack.push(buf); return std::make_pair(i + 1, Completed); } else @@ -313,7 +315,7 @@ std::pair RedisParser::parseChunk(const char * case ArraySize: if( c == '\r' ) { - if( string.empty() ) + if( buf.empty() ) { state = Start; return std::make_pair(i + 1, Error); @@ -325,7 +327,7 @@ std::pair RedisParser::parseChunk(const char * } else if( isdigit(c) || c == '-' ) { - string += c; + buf.push_back(c); } else { @@ -336,8 +338,10 @@ std::pair RedisParser::parseChunk(const char * case ArraySizeLF: if( c == '\n' ) { - long int arraySize = strtol(string.c_str(), 0, 10); - string.clear(); + // TODO optimize me + std::string tmp(buf.begin(), buf.end()); + long int arraySize = strtol(tmp.c_str(), 0, 10); + buf.clear(); std::vector array; if( arraySize == -1 || arraySize == 0) @@ -380,7 +384,7 @@ std::pair RedisParser::parseChunk(const char * case Integer: if( c == '\r' ) { - if( string.empty() ) + if( buf.empty() ) { state = Start; return std::make_pair(i + 1, Error); @@ -392,7 +396,7 @@ std::pair RedisParser::parseChunk(const char * } else if( isdigit(c) || c == '-' ) { - string += c; + buf.push_back(c); } else { @@ -403,9 +407,11 @@ std::pair RedisParser::parseChunk(const char * case IntegerLF: if( c == '\n' ) { - long int value = strtol(string.c_str(), 0, 10); + // TODO optimize me + std::string tmp(buf.begin(), buf.end()); + long int value = strtol(tmp.c_str(), 0, 10); - string.clear(); + buf.clear(); valueStack.push(value); state = Start; diff --git a/src/redisclient/impl/redissyncclient.cpp b/src/redisclient/impl/redissyncclient.cpp index 0659e82..6f71973 100644 --- a/src/redisclient/impl/redissyncclient.cpp +++ b/src/redisclient/impl/redissyncclient.cpp @@ -60,7 +60,7 @@ RedisValue RedisSyncClient::command(const std::string &s) { if(stateValid()) { - std::vector items(1); + std::vector items(1); items[0] = s; return pimpl->doSyncCommand(items); @@ -75,9 +75,9 @@ RedisValue RedisSyncClient::command(const std::string &cmd, const RedisBuffer &a { if(stateValid()) { - std::vector items(2); + std::vector items(2); items[0] = cmd; - items[1] = std::string(arg1.data(), arg1.data() + arg1.size()); + items[1] = arg1; return pimpl->doSyncCommand(items); } @@ -92,10 +92,10 @@ RedisValue RedisSyncClient::command(const std::string &cmd, const RedisBuffer &a { if(stateValid()) { - std::vector items(3); + std::vector items(3); items[0] = cmd; - items[1] = std::string(arg1.data(), arg1.data() + arg1.size()); - items[2] = std::string(arg2.data(), arg2.data() + arg2.size()); + items[1] = arg1; + items[2] = arg2; return pimpl->doSyncCommand(items); } @@ -110,11 +110,11 @@ RedisValue RedisSyncClient::command(const std::string &cmd, const RedisBuffer &a { if(stateValid()) { - std::vector items(4); + std::vector items(4); items[0] = cmd; - items[1] = std::string(arg1.data(), arg1.data() + arg1.size()); - items[2] = std::string(arg2.data(), arg2.data() + arg2.size()); - items[3] = std::string(arg3.data(), arg3.data() + arg3.size()); + items[1] = arg1; + items[2] = arg2; + items[3] = arg3; return pimpl->doSyncCommand(items); } @@ -130,12 +130,12 @@ RedisValue RedisSyncClient::command(const std::string &cmd, const RedisBuffer &a { if(stateValid()) { - std::vector items(5); + std::vector items(5); items[0] = cmd; - items[1] = std::string(arg1.data(), arg1.data() + arg1.size()); - items[2] = std::string(arg2.data(), arg2.data() + arg2.size()); - items[3] = std::string(arg3.data(), arg3.data() + arg3.size()); - items[4] = std::string(arg4.data(), arg4.data() + arg4.size()); + items[1] = arg1; + items[2] = arg2; + items[3] = arg3; + items[4] = arg4; return pimpl->doSyncCommand(items); } @@ -151,13 +151,13 @@ RedisValue RedisSyncClient::command(const std::string &cmd, const RedisBuffer &a { if(stateValid()) { - std::vector items(6); + std::vector items(6); items[0] = cmd; - items[1] = std::string(arg1.data(), arg1.data() + arg1.size()); - items[2] = std::string(arg2.data(), arg2.data() + arg2.size()); - items[3] = std::string(arg3.data(), arg3.data() + arg3.size()); - items[4] = std::string(arg4.data(), arg4.data() + arg4.size()); - items[5] = std::string(arg5.data(), arg5.data() + arg5.size()); + items[1] = arg1; + items[2] = arg2; + items[3] = arg3; + items[4] = arg4; + items[5] = arg5; return pimpl->doSyncCommand(items); } @@ -174,14 +174,14 @@ RedisValue RedisSyncClient::command(const std::string &cmd, const RedisBuffer &a { if(stateValid()) { - std::vector items(7); + std::vector items(7); items[0] = cmd; - items[1] = std::string(arg1.data(), arg1.data() + arg1.size()); - items[2] = std::string(arg2.data(), arg2.data() + arg2.size()); - items[3] = std::string(arg3.data(), arg3.data() + arg3.size()); - items[4] = std::string(arg4.data(), arg4.data() + arg4.size()); - items[5] = std::string(arg5.data(), arg5.data() + arg5.size()); - items[6] = std::string(arg6.data(), arg6.data() + arg6.size()); + items[1] = arg1; + items[2] = arg2; + items[3] = arg3; + items[4] = arg4; + items[5] = arg5; + items[6] = arg6; return pimpl->doSyncCommand(items); } @@ -198,15 +198,15 @@ RedisValue RedisSyncClient::command(const std::string &cmd, const RedisBuffer &a { if(stateValid()) { - std::vector items(8); + std::vector items(8); items[0] = cmd; - items[1] = std::string(arg1.data(), arg1.data() + arg1.size()); - items[2] = std::string(arg2.data(), arg2.data() + arg2.size()); - items[3] = std::string(arg3.data(), arg3.data() + arg3.size()); - items[4] = std::string(arg4.data(), arg4.data() + arg4.size()); - items[5] = std::string(arg5.data(), arg5.data() + arg5.size()); - items[6] = std::string(arg6.data(), arg6.data() + arg6.size()); - items[7] = std::string(arg7.data(), arg7.data() + arg7.size()); + items[1] = arg1; + items[2] = arg2; + items[3] = arg3; + items[4] = arg4; + items[5] = arg5; + items[6] = arg6; + items[7] = arg7; return pimpl->doSyncCommand(items); } @@ -220,7 +220,7 @@ RedisValue RedisSyncClient::command(const std::string &cmd, const std::list items(1); + std::vector items(1); items[0] = cmd; items.reserve(1 + args.size()); diff --git a/src/redisclient/impl/redisvalue.cpp b/src/redisclient/impl/redisvalue.cpp index cc239e9..dfab4c9 100644 --- a/src/redisclient/impl/redisvalue.cpp +++ b/src/redisclient/impl/redisvalue.cpp @@ -20,12 +20,17 @@ RedisValue::RedisValue(int i) } RedisValue::RedisValue(const char *s) - : value( std::string(s) ) + : value( std::vector(s, s + strlen(s)) ) { } RedisValue::RedisValue(const std::string &s) - : value(s) + : value( std::vector(s.begin(), s.end()) ) +{ +} + +RedisValue::RedisValue(const std::vector &buf) + : value(buf) { } @@ -41,7 +46,13 @@ std::vector RedisValue::toArray() const std::string RedisValue::toString() const { - return castTo(); + const std::vector &buf = toByteArray(); + return std::string(buf.begin(), buf.end()); +} + +std::vector RedisValue::toByteArray() const +{ + return castTo >(); } int RedisValue::toInt() const @@ -101,7 +112,12 @@ bool RedisValue::isInt() const bool RedisValue::isString() const { - return typeEq(); + return typeEq >(); +} + +bool RedisValue::isByteArray() const +{ + return typeEq >(); } bool RedisValue::isArray() const diff --git a/src/redisclient/redisasyncclient.h b/src/redisclient/redisasyncclient.h index 7fd4361..2533c50 100644 --- a/src/redisclient/redisasyncclient.h +++ b/src/redisclient/redisasyncclient.h @@ -15,6 +15,7 @@ #include "impl/redisclientimpl.h" #include "redisvalue.h" +#include "redisbuffer.h" #include "config.h" class RedisClientImpl; @@ -70,53 +71,53 @@ class RedisAsyncClient : boost::noncopyable { // Execute command on Redis server with one argument. REDIS_CLIENT_DECL void command( - const std::string &cmd, const std::string &arg1, + const std::string &cmd, const RedisBuffer &arg1, const boost::function &handler = &dummyHandler); // Execute command on Redis server with two arguments. REDIS_CLIENT_DECL void command( - const std::string &cmd, const std::string &arg1, const std::string &arg2, + const std::string &cmd, const RedisBuffer &arg1, const RedisBuffer &arg2, const boost::function &handler = &dummyHandler); // Execute command on Redis server with three arguments. REDIS_CLIENT_DECL void command( - const std::string &cmd, const std::string &arg1, - const std::string &arg2, const std::string &arg3, + const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const RedisBuffer &arg3, const boost::function &handler = &dummyHandler); // Execute command on Redis server with four arguments. REDIS_CLIENT_DECL void command( - const std::string &cmd, const std::string &arg1, const std::string &arg2, - const std::string &arg3, const std::string &arg4, + const std::string &cmd, const RedisBuffer &arg1, const RedisBuffer &arg2, + const RedisBuffer &arg3, const RedisBuffer &arg4, const boost::function &handler = &dummyHandler); // Execute command on Redis server with five arguments. REDIS_CLIENT_DECL void command( - const std::string &cmd, const std::string &arg1, - const std::string &arg2, const std::string &arg3, - const std::string &arg4, const std::string &arg5, + const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const RedisBuffer &arg3, + const RedisBuffer &arg4, const RedisBuffer &arg5, const boost::function &handler = &dummyHandler); // Execute command on Redis server with six arguments. REDIS_CLIENT_DECL void command( - const std::string &cmd, const std::string &arg1, - const std::string &arg2, const std::string &arg3, - const std::string &arg4, const std::string &arg5, - const std::string &arg6, + const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const RedisBuffer &arg3, + const RedisBuffer &arg4, const RedisBuffer &arg5, + const RedisBuffer &arg6, const boost::function &handler = &dummyHandler); // Execute command on Redis server with seven arguments. REDIS_CLIENT_DECL void command( - const std::string &cmd, const std::string &arg1, - const std::string &arg2, const std::string &arg3, - const std::string &arg4, const std::string &arg5, - const std::string &arg6, const std::string &arg7, + const std::string &cmd, const RedisBuffer &arg1, + const RedisBuffer &arg2, const RedisBuffer &arg3, + const RedisBuffer &arg4, const RedisBuffer &arg5, + const RedisBuffer &arg6, const RedisBuffer &arg7, const boost::function &handler = &dummyHandler); // Execute command on Redis server with the list of arguments. REDIS_CLIENT_DECL void command( - const std::string &cmd, const std::list &args, + const std::string &cmd, const std::list &args, const boost::function &handler = &dummyHandler); // Subscribe to channel. Handler msgHandler will be called @@ -124,7 +125,7 @@ class RedisAsyncClient : boost::noncopyable { // to stop the subscription. REDIS_CLIENT_DECL Handle subscribe( const std::string &channelName, - const boost::function &msgHandler, + const boost::function &msg)> &msgHandler, const boost::function &handler = &dummyHandler); // Unsubscribe @@ -135,12 +136,12 @@ class RedisAsyncClient : boost::noncopyable { // unsubscribed after call. REDIS_CLIENT_DECL void singleShotSubscribe( const std::string &channel, - const boost::function &msgHandler, + const boost::function &msg)> &msgHandler, const boost::function &handler = &dummyHandler); // Publish message on channel. REDIS_CLIENT_DECL void publish( - const std::string &channel, const std::string &msg, + const std::string &channel, const RedisBuffer &msg, const boost::function &handler = &dummyHandler); REDIS_CLIENT_DECL static void dummyHandler(const RedisValue &) {} diff --git a/src/redisclient/redisbuffer.h b/src/redisclient/redisbuffer.h index eb78138..5bcdda0 100644 --- a/src/redisclient/redisbuffer.h +++ b/src/redisclient/redisbuffer.h @@ -14,8 +14,10 @@ #include "config.h" -class RedisBuffer : boost::noncopyable { +class RedisBuffer +{ public: + inline RedisBuffer(); inline RedisBuffer(const char *ptr, size_t size); inline RedisBuffer(const char *s); inline RedisBuffer(const std::string &s); @@ -26,10 +28,15 @@ class RedisBuffer : boost::noncopyable { private: const char *ptr_; - const size_t size_; + size_t size_; }; +RedisBuffer::RedisBuffer() + : ptr_(NULL), size_(0) +{ +} + RedisBuffer::RedisBuffer(const char *ptr, size_t size) : ptr_(ptr), size_(size) { diff --git a/src/redisclient/redisparser.h b/src/redisclient/redisparser.h index 0028fd9..d1d57bd 100644 --- a/src/redisclient/redisparser.h +++ b/src/redisclient/redisparser.h @@ -7,6 +7,7 @@ #define REDISCLIENT_REDISPARSER_H #include +#include #include "redisvalue.h" #include "config.h" @@ -65,7 +66,7 @@ class RedisParser } state; long int bulkSize; - std::string string; + std::vector buf; std::stack arrayStack; std::stack valueStack; diff --git a/src/redisclient/redisvalue.h b/src/redisclient/redisvalue.h index 975529a..648ee29 100644 --- a/src/redisclient/redisvalue.h +++ b/src/redisclient/redisvalue.h @@ -18,11 +18,16 @@ class RedisValue { REDIS_CLIENT_DECL RedisValue(int i); REDIS_CLIENT_DECL RedisValue(const char *s); REDIS_CLIENT_DECL RedisValue(const std::string &s); + REDIS_CLIENT_DECL RedisValue(const std::vector &buf); REDIS_CLIENT_DECL RedisValue(const std::vector &array); // Return the value as a std::string if - // type is a std::string; otherwise returns an empty std::string. + // type is a byte string; otherwise returns an empty std::string. REDIS_CLIENT_DECL std::string toString() const; + + // Return the value as a std::vector if + // type is a byte string; otherwise returns an empty std::vector. + REDIS_CLIENT_DECL std::vector toByteArray() const; // Return the value as a std::vector if // type is an int; otherwise returns 0. @@ -40,10 +45,12 @@ class RedisValue { REDIS_CLIENT_DECL bool isNull() const; // Return true if type is an int REDIS_CLIENT_DECL bool isInt() const; - // Return true if type is a string - REDIS_CLIENT_DECL bool isString() const; // Return true if type is an array REDIS_CLIENT_DECL bool isArray() const; + // Return true if type is a string/byte array. Alias for isString(); + REDIS_CLIENT_DECL bool isByteArray() const; + // Return true if type is a string/byte array. Alias for isByteArray(). + REDIS_CLIENT_DECL bool isString() const; REDIS_CLIENT_DECL bool operator == (const RedisValue &rhs) const; REDIS_CLIENT_DECL bool operator != (const RedisValue &rhs) const; @@ -63,7 +70,7 @@ class RedisValue { }; - boost::variant > value; + boost::variant, std::vector > value; }; From f73307d62cd5b99205e8dbc63a3442248e903051 Mon Sep 17 00:00:00 2001 From: Robert burner Schadek Date: Thu, 2 Apr 2015 14:45:31 +0200 Subject: [PATCH 04/21] name shadowing fix (no bugs just less warnings) * it -> jt * queue to localQueue localQueue -> queueName --- src/redisclient/impl/redisclientimpl.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/redisclient/impl/redisclientimpl.cpp b/src/redisclient/impl/redisclientimpl.cpp index bc2a3f7..260b02d 100644 --- a/src/redisclient/impl/redisclientimpl.cpp +++ b/src/redisclient/impl/redisclientimpl.cpp @@ -56,14 +56,14 @@ void RedisClientImpl::doProcessMessage(const RedisValue &v) if( result.size() == 3 ) { const RedisValue &command = result[0]; - const RedisValue &queue = result[1]; + const RedisValue &queueName = result[1]; const RedisValue &value = result[2]; const std::string &cmd = command.toString(); if( cmd == "message" ) { - SingleShotHandlersMap::iterator it = singleShotMsgHandlers.find(queue.toString()); + SingleShotHandlersMap::iterator it = singleShotMsgHandlers.find(queueName.toString()); if( it != singleShotMsgHandlers.end() ) { strand.post(boost::bind(it->second, value.toString())); @@ -71,9 +71,9 @@ void RedisClientImpl::doProcessMessage(const RedisValue &v) } std::pair pair = - msgHandlers.equal_range(queue.toString()); - for(MsgHandlersMap::iterator it = pair.first; it != pair.second; ++it) - strand.post(boost::bind(it->second.second, value.toString())); + msgHandlers.equal_range(queueName.toString()); + for(MsgHandlersMap::iterator jt = pair.first; jt != pair.second; ++jt) + strand.post(boost::bind(jt->second.second, value.toString())); } else if( cmd == "subscribe" && handlers.empty() == false ) { From 989062cfac482e13d24fe30e95769d900844f3e3 Mon Sep 17 00:00:00 2001 From: Robert burner Schadek Date: Tue, 7 Apr 2015 11:47:23 +0200 Subject: [PATCH 05/21] another name clash and some const --- src/redisclient/impl/redisclient.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/redisclient/impl/redisclient.cpp b/src/redisclient/impl/redisclient.cpp index 8255c6f..f057356 100644 --- a/src/redisclient/impl/redisclient.cpp +++ b/src/redisclient/impl/redisclient.cpp @@ -9,6 +9,8 @@ #include #include "../redisclient.h" +static const std::string subscribeStr = "SUBSCRIBE"; + RedisClient::RedisClient(boost::asio::io_service &ioService) : pimpl(boost::make_shared(boost::ref(ioService))) { @@ -221,14 +223,12 @@ RedisClient::Handle RedisClient::subscribe( assert( pimpl->state == RedisClientImpl::Connected || pimpl->state == RedisClientImpl::Subscribed); - static std::string subscribe = "SUBSCRIBE"; - if( pimpl->state == RedisClientImpl::Connected || pimpl->state == RedisClientImpl::Subscribed ) { Handle handle = {pimpl->subscribeSeq++, channel}; std::vector items(2); - items[0] = subscribe; + items[0] = subscribeStr; items[1] = channel; pimpl->post(boost::bind(&RedisClientImpl::doCommand, pimpl, items, handler)); @@ -259,7 +259,7 @@ void RedisClient::unsubscribe(const Handle &handle) assert( pimpl->state == RedisClientImpl::Connected || pimpl->state == RedisClientImpl::Subscribed); - static std::string unsubscribe = "UNSUBSCRIBE"; + static const std::string unsubscribeStr = "UNSUBSCRIBE"; if( pimpl->state == RedisClientImpl::Connected || pimpl->state == RedisClientImpl::Subscribed ) @@ -281,7 +281,7 @@ void RedisClient::unsubscribe(const Handle &handle) } std::vector items(2); - items[0] = unsubscribe; + items[0] = unsubscribeStr; items[1] = handle.channel; // Unsubscribe command for Redis @@ -313,13 +313,11 @@ void RedisClient::singleShotSubscribe(const std::string &channel, assert( pimpl->state == RedisClientImpl::Connected || pimpl->state == RedisClientImpl::Subscribed); - static std::string subscribe = "SUBSCRIBE"; - if( pimpl->state == RedisClientImpl::Connected || pimpl->state == RedisClientImpl::Subscribed ) { std::vector items(2); - items[0] = subscribe; + items[0] = subscribeStr; items[1] = channel; pimpl->post(boost::bind(&RedisClientImpl::doCommand, pimpl, items, handler)); @@ -343,13 +341,13 @@ void RedisClient::publish(const std::string &channel, const std::string &msg, { assert( pimpl->state == RedisClientImpl::Connected ); - static std::string publish = "PUBLISH"; + static const std::string publishStr = "PUBLISH"; if( pimpl->state == RedisClientImpl::Connected ) { std::vector items(3); - items[0] = publish; + items[0] = publishStr; items[1] = channel; items[2] = msg; From 72d0ee3352b64950771788b31eae1ec923326956 Mon Sep 17 00:00:00 2001 From: Alex Nekipelov Date: Tue, 14 Apr 2015 19:24:13 +0300 Subject: [PATCH 06/21] simplified example --- examples/sync_set_get.cpp | 45 ++++++++------------------------------- 1 file changed, 9 insertions(+), 36 deletions(-) diff --git a/examples/sync_set_get.cpp b/examples/sync_set_get.cpp index 1b8e00a..6d671ec 100644 --- a/examples/sync_set_get.cpp +++ b/examples/sync_set_get.cpp @@ -21,46 +21,19 @@ int main(int, char **) } const std::string key = "unique-redis-key-example"; - const char rawValue [] = "unique-redis-value"; - const std::string stringValue(rawValue, rawValue + sizeof(rawValue) - 1); - const std::vector vectorValue(rawValue, rawValue + sizeof(rawValue) - 1); + const char value [] = "unique-redis-value"; - { - // raw - redis.command("SET", key, rawValue); - RedisValue value = redis.command("GET", key); - - if( value.toString() != rawValue ) - { - std::cerr << "Invalid value from redis: " << value.toString() << std::endl; - return EXIT_FAILURE; - } - } - - { - // std::string - redis.command("SET", key, stringValue); - RedisValue value = redis.command("GET", key); - - if( value.toString() != stringValue ) - { - std::cerr << "Invalid value from redis: " << value.toString() << std::endl; - return EXIT_FAILURE; - } - } + redis.command("SET", key, value); + RedisValue result = redis.command("GET", key); - { - // vector - redis.command("SET", key, vectorValue); - RedisValue value = redis.command("GET", key); + std::cout << "SET " << key << ": " << value << "\n"; + std::cout << "GET " << key << ": " << result.toString() << "\n"; - if( value.toByteArray() != vectorValue ) - { - std::cerr << "Invalid value from redis: " << value.toString() << std::endl; - return EXIT_FAILURE; - } + if( result.toString() != value ) + { + std::cerr << "Invalid value from redis: " << result.toString() << std::endl; + return EXIT_FAILURE; } - return EXIT_SUCCESS; } From f7bedecdb766898f0d9225d7e074c4ad825d3442 Mon Sep 17 00:00:00 2001 From: Alex Nekipelov Date: Tue, 14 Apr 2015 19:25:01 +0300 Subject: [PATCH 07/21] new example --- examples/async_pubsub2.cpp | 78 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 examples/async_pubsub2.cpp diff --git a/examples/async_pubsub2.cpp b/examples/async_pubsub2.cpp new file mode 100644 index 0000000..19eb022 --- /dev/null +++ b/examples/async_pubsub2.cpp @@ -0,0 +1,78 @@ +#include +#include +#include +#include + +#include + +static const std::string channelName = "unique-redis-channel-name-example"; + + +class Client +{ +public: + Client(boost::asio::io_service &ioService) + : ioService(ioService) + {} + + void onMessage(const std::vector &buf) + { + std::string msg(buf.begin(), buf.end()); + + std::cerr << "Message: " << msg << std::endl; + + if( msg == "stop" ) + ioService.stop(); + } + +private: + boost::asio::io_service &ioService; +}; + +void publishHandler(RedisAsyncClient &publisher, const RedisValue &) +{ + publisher.publish(channelName, "First hello", [&](const RedisValue &) { + publisher.publish(channelName, "Last hello", [&](const RedisValue &) { + publisher.publish(channelName, "stop"); + }); + }); +} + +int main(int, char **) +{ + boost::asio::ip::address address = boost::asio::ip::address::from_string("127.0.0.1"); + const unsigned short port = 6379; + + boost::asio::io_service ioService; + RedisAsyncClient publisher(ioService); + RedisAsyncClient subscriber(ioService); + Client client(ioService); + + publisher.asyncConnect(address, port, [&](bool status, const std::string &err) + { + if( !status ) + { + std::cerr << "Can't connect to to redis" << err << std::endl; + } + else + { + subscriber.asyncConnect(address, port, [&](bool status, const std::string &err) + { + if( !status ) + { + std::cerr << "Can't connect to to redis" << err << std::endl; + } + else + { + subscriber.subscribe(channelName, + boost::bind(&Client::onMessage, &client, _1), + boost::bind(&publishHandler, boost::ref(publisher), _1)); + } + }); + } + }); + + ioService.run(); + + return 0; +} From b77748d2e471636feff915a803a45c8f1b5a0639 Mon Sep 17 00:00:00 2001 From: Alex Nekipelov Date: Tue, 14 Apr 2015 19:46:22 +0300 Subject: [PATCH 08/21] Shadow warnings --- src/redisclient/impl/redisasyncclient.cpp | 16 ++++++++-------- src/redisclient/impl/redisclientimpl.cpp | 13 ++++++++----- src/redisclient/impl/redisparser.cpp | 6 +++--- src/redisclient/redisbuffer.h | 6 +++--- 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/redisclient/impl/redisasyncclient.cpp b/src/redisclient/impl/redisasyncclient.cpp index 7fd8e12..3633d24 100644 --- a/src/redisclient/impl/redisasyncclient.cpp +++ b/src/redisclient/impl/redisasyncclient.cpp @@ -210,14 +210,14 @@ RedisAsyncClient::Handle RedisAsyncClient::subscribe( assert( pimpl->state == RedisClientImpl::Connected || pimpl->state == RedisClientImpl::Subscribed); - static const std::string subscribe = "SUBSCRIBE"; + static const std::string subscribeStr = "SUBSCRIBE"; if( pimpl->state == RedisClientImpl::Connected || pimpl->state == RedisClientImpl::Subscribed ) { Handle handle = {pimpl->subscribeSeq++, channel}; std::vector items(2); - items[0] = subscribe; + items[0] = subscribeStr; items[1] = channel; pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, @@ -249,7 +249,7 @@ void RedisAsyncClient::unsubscribe(const Handle &handle) assert( pimpl->state == RedisClientImpl::Connected || pimpl->state == RedisClientImpl::Subscribed); - static const std::string unsubscribe = "UNSUBSCRIBE"; + static const std::string unsubscribeStr = "UNSUBSCRIBE"; if( pimpl->state == RedisClientImpl::Connected || pimpl->state == RedisClientImpl::Subscribed ) @@ -271,7 +271,7 @@ void RedisAsyncClient::unsubscribe(const Handle &handle) } std::vector items(2); - items[0] = unsubscribe; + items[0] = unsubscribeStr; items[1] = handle.channel; // Unsubscribe command for Redis @@ -304,13 +304,13 @@ void RedisAsyncClient::singleShotSubscribe(const std::string &channel, assert( pimpl->state == RedisClientImpl::Connected || pimpl->state == RedisClientImpl::Subscribed); - static const std::string subscribe = "SUBSCRIBE"; + static const std::string subscribeStr = "SUBSCRIBE"; if( pimpl->state == RedisClientImpl::Connected || pimpl->state == RedisClientImpl::Subscribed ) { std::vector items(2); - items[0] = subscribe; + items[0] = subscribeStr; items[1] = channel; pimpl->post(boost::bind(&RedisClientImpl::doAsyncCommand, pimpl, @@ -335,13 +335,13 @@ void RedisAsyncClient::publish(const std::string &channel, const RedisBuffer &ms { assert( pimpl->state == RedisClientImpl::Connected ); - static const std::string publish = "PUBLISH"; + static const std::string publishStr = "PUBLISH"; if( pimpl->state == RedisClientImpl::Connected ) { std::vector items(3); - items[0] = publish; + items[0] = publishStr; items[1] = channel; items[2] = msg; diff --git a/src/redisclient/impl/redisclientimpl.cpp b/src/redisclient/impl/redisclientimpl.cpp index 8279426..a8e1222 100644 --- a/src/redisclient/impl/redisclientimpl.cpp +++ b/src/redisclient/impl/redisclientimpl.cpp @@ -55,14 +55,14 @@ void RedisClientImpl::doProcessMessage(const RedisValue &v) if( result.size() == 3 ) { const RedisValue &command = result[0]; - const RedisValue &queue = result[1]; + const RedisValue &queueName = result[1]; const RedisValue &value = result[2]; const std::string &cmd = command.toString(); if( cmd == "message" ) { - SingleShotHandlersMap::iterator it = singleShotMsgHandlers.find(queue.toString()); + SingleShotHandlersMap::iterator it = singleShotMsgHandlers.find(queueName.toString()); if( it != singleShotMsgHandlers.end() ) { strand.post(boost::bind(it->second, value.toByteArray())); @@ -70,9 +70,12 @@ void RedisClientImpl::doProcessMessage(const RedisValue &v) } std::pair pair = - msgHandlers.equal_range(queue.toString()); - for(MsgHandlersMap::iterator it = pair.first; it != pair.second; ++it) - strand.post(boost::bind(it->second.second, value.toByteArray())); + msgHandlers.equal_range(queueName.toString()); + for(MsgHandlersMap::iterator handlerIt = pair.first; + handlerIt != pair.second; ++handlerIt) + { + strand.post(boost::bind(handlerIt->second.second, value.toByteArray())); + } } else if( cmd == "subscribe" && handlers.empty() == false ) { diff --git a/src/redisclient/impl/redisparser.cpp b/src/redisclient/impl/redisparser.cpp index 11b5cc9..3bafdad 100644 --- a/src/redisclient/impl/redisparser.cpp +++ b/src/redisclient/impl/redisparser.cpp @@ -365,9 +365,9 @@ std::pair RedisParser::parseChunk(const char * if( i + 1 != size ) { - std::pair result = parseArray(ptr + i + 1, size - i - 1); - result.first += i + 1; - return result; + std::pair result_ = parseArray(ptr + i + 1, size - i - 1); + result_.first += i + 1; + return result_; } else { diff --git a/src/redisclient/redisbuffer.h b/src/redisclient/redisbuffer.h index 5bcdda0..9cda55f 100644 --- a/src/redisclient/redisbuffer.h +++ b/src/redisclient/redisbuffer.h @@ -18,7 +18,7 @@ class RedisBuffer { public: inline RedisBuffer(); - inline RedisBuffer(const char *ptr, size_t size); + inline RedisBuffer(const char *ptr, size_t dataSize); inline RedisBuffer(const char *s); inline RedisBuffer(const std::string &s); inline RedisBuffer(const std::vector &buf); @@ -37,8 +37,8 @@ RedisBuffer::RedisBuffer() { } -RedisBuffer::RedisBuffer(const char *ptr, size_t size) - : ptr_(ptr), size_(size) +RedisBuffer::RedisBuffer(const char *ptr, size_t dataSize) + : ptr_(ptr), size_(dataSize) { } From 524f6f3a2bce3ee496715a8b78ffc03b356cc9e7 Mon Sep 17 00:00:00 2001 From: Alex Nekipelov Date: Tue, 14 Apr 2015 19:47:34 +0300 Subject: [PATCH 09/21] CMake project files --- .travis.yml | 5 +++- CMakeLists.txt | 58 +++++++++++++++++++++++++++++++++++++++++ Makefile | 28 -------------------- examples/CMakeLists.txt | 43 ++++++++++++++++++++++++++++++ examples/Makefile | 22 ---------------- 5 files changed, 105 insertions(+), 51 deletions(-) create mode 100644 CMakeLists.txt delete mode 100644 Makefile create mode 100644 examples/CMakeLists.txt delete mode 100644 examples/Makefile diff --git a/.travis.yml b/.travis.yml index 347031c..1753e84 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,4 +15,7 @@ before_script: - sudo apt-get install -qq libboost-dev libboost-test-dev libboost-system-dev script: - - make && make test && make -C examples + - cmake + - make + - make test + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3d00b76 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,58 @@ +cmake_minimum_required(VERSION 2.6) + +PROJECT(RedisClient) + +FIND_PACKAGE(Boost COMPONENTS unit_test_framework system REQUIRED) + +SET(CMAKE_CXX_FLAGS "-W -Wall -Wextra -Wshadow -fPIC -pthread") +SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3 -DDEBUG ") +SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") + +SET(SOURCES + src/redisclient/impl/redisvalue.cpp + src/redisclient/impl/redissyncclient.cpp + src/redisclient/impl/redisparser.cpp + src/redisclient/impl/redisclientimpl.cpp + src/redisclient/impl/redisasyncclient.cpp +) + +SET(HEADERS + src/redisclient/config.h + src/redisclient/version.h + src/redisclient/redisvalue.h + src/redisclient/redissyncclient.h + src/redisclient/redisparser.h + src/redisclient/redisclient.h + src/redisclient/redisbuffer.h + src/redisclient/redisasyncclient.h + src/redisclient/impl/redisclientimpl.h +) + +INCLUDE_DIRECTORIES( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${Boost_INCLUDE_DIRS} +) + +ADD_EXECUTABLE(parsertest tests/parsertest.cpp ${SOURCES} ${HEADERS}) +ADD_LIBRARY(redisclient STATIC ${HEADERS} ${SOURCES}) + +TARGET_LINK_LIBRARIES(parsertest + ${Boost_LIBRARIES} +) + +TARGET_LINK_LIBRARIES(redisclient + ${Boost_LIBRARIES} +) + +INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/src DESTINATION include) + +ADD_CUSTOM_TARGET ( test) +ADD_CUSTOM_COMMAND(TARGET test + POST_BUILD + COMMAND ./parsertest + COMMENT "Run tests" + VERBATIM +) + +ADD_SUBDIRECTORY(examples) diff --git a/Makefile b/Makefile deleted file mode 100644 index de62b29..0000000 --- a/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -SRCS = src/redisclient/impl/redissyncclient.cpp src/redisclient/impl/redisasyncclient.cpp src/redisclient/impl/redisvalue.cpp src/redisclient/impl/redisparser.cpp -HDRS = src/redisasyncclient.h src/redissyncclient.h src/redisvalie.h src/redisparser.h -OBJS = $(SRCS:.cpp=.o) -LIBNAME = redisclient -LIB = lib$(LIBNAME).so -LIBS = -pthread -lboost_system -LDFLAGS = -g -shared -CXXFLAGS = -g -O2 -Wall -Wextra -fPIC -std=c++11 -DREDIS_CLIENT_DYNLIB -DREDIS_CLIENT_BUILD - -all: test -dynlib: $(LIB) -$(LIB): $(OBJS) - $(CXX) $^ -o $@ $(LDFLAGS) -examples: $(LIB) - +make -C examples examples -tests: test -test: - +make -C tests test - -.cpp.o: - $(CXX) $(CXXFLAGS) -c $< -o $@ - -clean: - rm -f $(OBJS) - make -C tests clean - make -C examples clean - -.PHONY: all test clean examples diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..7dc8d65 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,43 @@ +cmake_minimum_required(VERSION 2.6) + +FIND_PACKAGE(Boost COMPONENTS system REQUIRED) + +SET(CMAKE_CXX_FLAGS "-W -Wall -Wextra -fPIC -pthread -std=c++11") +SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3 -DDEBUG ") +SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") + +SET(REDISCLIENT_SOURCES + ${CMAKE_SOURCE_DIR}/src/redisclient/impl/redisvalue.cpp + ${CMAKE_SOURCE_DIR}/src/redisclient/impl/redissyncclient.cpp + ${CMAKE_SOURCE_DIR}/src/redisclient/impl/redisparser.cpp + ${CMAKE_SOURCE_DIR}/src/redisclient/impl/redisclientimpl.cpp + ${CMAKE_SOURCE_DIR}/src/redisclient/impl/redisasyncclient.cpp + ${CMAKE_SOURCE_DIR}/src/redisclient/config.h + ${CMAKE_SOURCE_DIR}/src/redisclient/version.h + ${CMAKE_SOURCE_DIR}/src/redisclient/redisvalue.h + ${CMAKE_SOURCE_DIR}/src/redisclient/redissyncclient.h + ${CMAKE_SOURCE_DIR}/src/redisclient/redisparser.h + ${CMAKE_SOURCE_DIR}/src/redisclient/redisclient.h + ${CMAKE_SOURCE_DIR}/src/redisclient/redisbuffer.h + ${CMAKE_SOURCE_DIR}/src/redisclient/redisasyncclient.h + ${CMAKE_SOURCE_DIR}/src/redisclient/impl/redisclientimpl.h +) + +INCLUDE_DIRECTORIES( + ${Boost_INCLUDE_DIRS} + ${CMAKE_SOURCE_DIR}/src/ +) + +SET(EXAMPLES + async_pubsub2.cpp + async_pubsub.cpp + async_set_get2.cpp + async_set_get.cpp + sync_set_get.cpp +) + +FOREACH(EXAMPLE ${EXAMPLES}) + GET_FILENAME_COMPONENT(EXECUTABLE ${EXAMPLE} NAME_WE) + ADD_EXECUTABLE(${EXECUTABLE} ${EXAMPLE} ${REDISCLIENT_SOURCES}) + TARGET_LINK_LIBRARIES(${EXECUTABLE} ${Boost_LIBRARIES}) +ENDFOREACH(EXAMPLE) diff --git a/examples/Makefile b/examples/Makefile deleted file mode 100644 index c801559..0000000 --- a/examples/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -LDFLAGS = -g -pthread -lboost_system -CXXFLAGS = -g -O2 -Wall -Wextra -I../src -std=c++11 - -EXAMPLES = async_pubsub async_set_get async_set_get2 sync_set_get -SOURCES = $(EXAMPLES:=.cpp) -OBJS = $(SOURCES:.cpp=.o) -DEPS = $(SOURCES:.cpp=.d) - -all: $(EXAMPLES) - -$(EXAMPLES): $(OBJS) - $(CXX) $(LDFLAGS) $@.o -o $@ - -%.o: %.cpp - $(CXX) $(CXXFLAGS) -MMD -c $< -o $@ - -clean: - rm -f $(OBJS) $(EXAMPLES) $(DEPS) - --include $(DEPS) - -.PHONY: clean From cfcca93023eef272b63aeeacd878f2f745c26c07 Mon Sep 17 00:00:00 2001 From: Alex Nekipelov Date: Tue, 14 Apr 2015 20:07:53 +0300 Subject: [PATCH 10/21] Update .travis.yml --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1753e84..c285b96 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,8 @@ before_script: - sudo apt-get install -qq libboost-dev libboost-test-dev libboost-system-dev script: - - cmake + - mkdir build && cd build + - cmake .. - make - make test From 17dadc90f81dbdf5dabea4dcfeb9acc41b2891d8 Mon Sep 17 00:00:00 2001 From: Alex Nekipelov Date: Tue, 14 Apr 2015 20:38:58 +0300 Subject: [PATCH 11/21] Update .travis.yml --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c285b96..e5eb46d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,9 +10,8 @@ before_install: install: - if [ "$CXX" == "g++" ]; then sudo apt-get install -qq g++-4.8; fi - if [ "$CXX" == "g++" ]; then sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50; fi - -before_script: - sudo apt-get install -qq libboost-dev libboost-test-dev libboost-system-dev + - dpkg -l "libboost*" script: - mkdir build && cd build From aa8356af2f74c8e1a60ecb7da95da5e7fca313db Mon Sep 17 00:00:00 2001 From: Alex Nekipelov Date: Wed, 15 Apr 2015 13:27:10 +0300 Subject: [PATCH 12/21] Fix compilation error with boost 1.46 --- src/redisclient/impl/redisclientimpl.cpp | 2 +- src/redisclient/impl/redisvalue.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/redisclient/impl/redisclientimpl.cpp b/src/redisclient/impl/redisclientimpl.cpp index a8e1222..e79c4fc 100644 --- a/src/redisclient/impl/redisclientimpl.cpp +++ b/src/redisclient/impl/redisclientimpl.cpp @@ -193,7 +193,7 @@ RedisValue RedisClientImpl::doSyncCommand(const std::vector &buff) { std::vector data = makeCommand(buff); - boost::asio::write(socket, boost::asio::buffer(data), ec); + boost::asio::write(socket, boost::asio::buffer(data), boost::asio::transfer_all(), ec); } if( ec ) diff --git a/src/redisclient/impl/redisvalue.cpp b/src/redisclient/impl/redisvalue.cpp index dfab4c9..1c0f2e8 100644 --- a/src/redisclient/impl/redisvalue.cpp +++ b/src/redisclient/impl/redisvalue.cpp @@ -6,6 +6,7 @@ #ifndef REDISCLIENT_REDISVALUE_CPP #define REDISCLIENT_REDISVALUE_CPP +#include #include #include "../redisvalue.h" From 57e3842d9893aef71dcea770c409809fda921f37 Mon Sep 17 00:00:00 2001 From: Alex Nekipelov Date: Wed, 15 Apr 2015 13:56:11 +0300 Subject: [PATCH 13/21] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e5eb46d..ca3c3b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ install: - if [ "$CXX" == "g++" ]; then sudo apt-get install -qq g++-4.8; fi - if [ "$CXX" == "g++" ]; then sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50; fi - sudo apt-get install -qq libboost-dev libboost-test-dev libboost-system-dev - - dpkg -l "libboost*" + - dpkg -l "libboost*" | sort script: - mkdir build && cd build From 898328c4d982203cb94efcb14941c845b7bc74eb Mon Sep 17 00:00:00 2001 From: Alex Nekipelov Date: Wed, 15 Apr 2015 17:22:25 +0300 Subject: [PATCH 14/21] Update .travis.yml --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ca3c3b7..dcc24f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,9 @@ before_install: install: - if [ "$CXX" == "g++" ]; then sudo apt-get install -qq g++-4.8; fi - if [ "$CXX" == "g++" ]; then sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50; fi - - sudo apt-get install -qq libboost-dev libboost-test-dev libboost-system-dev + - sudo apt-get install -qq libboost-dev + - sudo apt-get install -qq libboost-test-dev + - sudo apt-get install -qq libboost-system-dev - dpkg -l "libboost*" | sort script: From 3a720a2498dceba79f42aa8f319d8a15702cee43 Mon Sep 17 00:00:00 2001 From: Alex Nekipelov Date: Wed, 15 Apr 2015 18:13:56 +0300 Subject: [PATCH 15/21] Update .travis.yml --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index dcc24f0..c18d888 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,9 +10,7 @@ before_install: install: - if [ "$CXX" == "g++" ]; then sudo apt-get install -qq g++-4.8; fi - if [ "$CXX" == "g++" ]; then sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50; fi - - sudo apt-get install -qq libboost-dev - - sudo apt-get install -qq libboost-test-dev - - sudo apt-get install -qq libboost-system-dev + - sudo apt-get install -qq libboost1.48-dev libboost-test1.48-dev libboost-system1.48-dev - dpkg -l "libboost*" | sort script: From dc18d5e8dae135592a9b379b40c75d4899267f6b Mon Sep 17 00:00:00 2001 From: Robert burner Schadek Date: Tue, 14 Apr 2015 23:33:48 +0200 Subject: [PATCH 16/21] result name clash fix --- src/redisclient/impl/redisparser.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/redisclient/impl/redisparser.cpp b/src/redisclient/impl/redisparser.cpp index 18fce17..c84c138 100644 --- a/src/redisclient/impl/redisparser.cpp +++ b/src/redisclient/impl/redisparser.cpp @@ -361,9 +361,9 @@ std::pair RedisParser::parseChunk(const char * if( i + 1 != size ) { - std::pair result = parseArray(ptr + i + 1, size - i - 1); - result.first += i + 1; - return result; + std::pair parseResult = parseArray(ptr + i + 1, size - i - 1); + parseResult.first += i + 1; + return parseResult; } else { From 2b37be0731a6e01235a59ff57ade5342accfb00f Mon Sep 17 00:00:00 2001 From: Alex Nekipelov Date: Thu, 30 Apr 2015 15:12:53 +0300 Subject: [PATCH 17/21] README.md updated --- README.md | 139 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 101 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 7356f11..33c4fb6 100644 --- a/README.md +++ b/README.md @@ -9,75 +9,137 @@ Boost.asio based Redis-client header-only library. Simple but powerfull. Get/set example: - #include "redisclient.h" - - static const std::string redisKey = "unique-redis-key-example"; - static const std::string redisValue = "unique-redis-value"; + #include int main(int, char **) { - const char *address = "127.0.0.1"; - const int port = 6379; + boost::asio::ip::address address = boost::asio::ip::address::from_string("127.0.0.1"); + const unsigned short port = 6379; boost::asio::io_service ioService; - RedisClient redis(ioService); - - if( !redis.connect(address, port) ) + RedisSyncClient redis(ioService); + std::string errmsg; + + if( !redis.connect(address, port, errmsg) ) { - std::cerr << "Can't connecto to redis" << std::endl; + std::cerr << "Can't connect to redis: " << errmsg << std::endl; return EXIT_FAILURE; } - redis.command("SET", redisKey, redisValue, [&](const Value &v) { - std::cerr << "SET: " << v.toString() << std::endl; + const std::string key = "unique-redis-key-example"; + const char value [] = "unique-redis-value"; + + redis.command("SET", key, value); + RedisValue result = redis.command("GET", key); + + std::cout << "SET " << key << ": " << value << "\n"; + std::cout << "GET " << key << ": " << result.toString() << "\n"; + + return EXIT_SUCCESS; + } + +Async get/set example: + + #include + + static const std::string redisKey = "unique-redis-key-example"; + static const std::string redisValue = "unique-redis-value"; - redis.command("GET", redisKey, [&](const Value &v) { - std::cerr << "GET: " << v.toString() << std::endl; + void handleConnected(boost::asio::io_service &ioService, RedisAsyncClient &redis, + bool ok, const std::string &errmsg) + { + if( ok ) + { + redis.command("SET", redisKey, redisValue, [&](const RedisValue &v) { + std::cerr << "SET: " << v.toString() << std::endl; + + redis.command("GET", redisKey, [&](const RedisValue &v) { + std::cerr << "GET: " << v.toString() << std::endl; - redis.command("DEL", redisKey, [&](const Value &v) { - ioService.stop(); + redis.command("DEL", redisKey, [&](const RedisValue &) { + ioService.stop(); + }); }); }); - }); + } + else + { + std::cerr << "Can't connect to redis: " << errmsg << std::endl; + } + } + + int main(int, char **) + { + boost::asio::ip::address address = boost::asio::ip::address::from_string("127.0.0.1"); + const unsigned short port = 6379; + + boost::asio::io_service ioService; + RedisAsyncClient redis(ioService); + + redis.asyncConnect(address, port, + boost::bind(&handleConnected, boost::ref(ioService), boost::ref(redis), _1, _2)); ioService.run(); return 0; } + Publish/subscribe example: - #include "redisclient.h" + #include static const std::string channelName = "unique-redis-channel-name-example"; - int main(int, char **) + void subscribeHandler(boost::asio::io_service &ioService, const std::vector &buf) { - const char *address = "127.0.0.1"; - const int port = 6379; + std::string msg(buf.begin(), buf.end()); - boost::asio::io_service ioService; - RedisClient publisher(ioService); - RedisClient subscriber(ioService); + if( msg == "stop" ) + ioService.stop(); + } - if( !publisher.connect(address, port) || !subscriber.connect(address, port) ) - { - std::cerr << "Can't connecto to redis" << std::endl; - return EXIT_FAILURE; - } + void publishHandler(RedisAsyncClient &publisher, const RedisValue &) + { + publisher.publish(channelName, "First hello", [&](const RedisValue &) { + publisher.publish(channelName, "Last hello", [&](const RedisValue &) { + publisher.publish(channelName, "stop"); + }); + }); + } - subscriber.subscribe(channelName, [&](const std::string &msg) { - std::cerr << "Message: " << msg << std::endl; + int main(int, char **) + { + boost::asio::ip::address address = boost::asio::ip::address::from_string("127.0.0.1"); + const unsigned short port = 6379; - if( msg == "stop" ) - ioService.stop(); - }); + boost::asio::io_service ioService; + RedisAsyncClient publisher(ioService); + RedisAsyncClient subscriber(ioService); - publisher.publish(channelName, "First hello", [&](const Value &) { - publisher.publish(channelName, "Last hello", [&](const Value &) { - publisher.publish(channelName, "stop"); - }); + publisher.asyncConnect(address, port, [&](bool status, const std::string &err) + { + if( !status ) + { + std::cerr << "Can't connect to to redis" << err << std::endl; + } + else + { + subscriber.asyncConnect(address, port, [&](bool status, const std::string &err) + { + if( !status ) + { + std::cerr << "Can't connect to to redis" << err << std::endl; + } + else + { + subscriber.subscribe(channelName, + boost::bind(&subscribeHandler, boost::ref(ioService), _1), + boost::bind(&publishHandler, boost::ref(publisher), _1)); + } + }); + } }); ioService.run(); @@ -85,6 +147,7 @@ Publish/subscribe example: return 0; } + Also you can build the library like a shared library. Just use -DREDIS_CLIENT_DYNLIB and -DREDIS_CLIENT_BUILD to build redisclient and -DREDIS_CLIENT_DYNLIB to build your project. From 54549cf20b8cec62e33c2ee0a9e4f6d8bf253e88 Mon Sep 17 00:00:00 2001 From: Alex Nekipelov Date: Thu, 30 Apr 2015 15:46:44 +0300 Subject: [PATCH 18/21] isOk and isError methods for RedisValue --- CMakeLists.txt | 2 +- README.md | 28 ++++++++++++++------ examples/sync_set_get.cpp | 26 ++++++++++++------- src/redisclient/impl/redisparser.cpp | 15 ++++++++++- src/redisclient/impl/redisvalue.cpp | 39 +++++++++++++++++++++++----- src/redisclient/redisvalue.h | 10 +++++++ 6 files changed, 93 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d00b76..3e7c6e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,7 +47,7 @@ TARGET_LINK_LIBRARIES(redisclient INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/src DESTINATION include) -ADD_CUSTOM_TARGET ( test) +ADD_CUSTOM_TARGET(test) ADD_CUSTOM_COMMAND(TARGET test POST_BUILD COMMAND ./parsertest diff --git a/README.md b/README.md index 33c4fb6..8addb10 100644 --- a/README.md +++ b/README.md @@ -26,16 +26,28 @@ Get/set example: return EXIT_FAILURE; } - const std::string key = "unique-redis-key-example"; - const char value [] = "unique-redis-value"; + RedisValue result; - redis.command("SET", key, value); - RedisValue result = redis.command("GET", key); + result = redis.command("SET", "key", "value"); - std::cout << "SET " << key << ": " << value << "\n"; - std::cout << "GET " << key << ": " << result.toString() << "\n"; - - return EXIT_SUCCESS; + if( result.isError() ) + { + std::cerr << "SET error: " << result.toString() << "\n"; + return EXIT_FAILURE; + } + + result = redis.command("GET", "key"); + + if( result.isOk() ) + { + std::cout << "GET " << key << ": " << result.toString() << "\n"; + return EXIT_SUCCESS; + } + else + { + std::cerr << "GET error: " << result.toString() << "\n"; + return EXIT_FAILURE; + } } Async get/set example: diff --git a/examples/sync_set_get.cpp b/examples/sync_set_get.cpp index 6d671ec..4cb1892 100644 --- a/examples/sync_set_get.cpp +++ b/examples/sync_set_get.cpp @@ -20,20 +20,26 @@ int main(int, char **) return EXIT_FAILURE; } - const std::string key = "unique-redis-key-example"; - const char value [] = "unique-redis-value"; + RedisValue result; - redis.command("SET", key, value); - RedisValue result = redis.command("GET", key); + result = redis.command("SET", "key", "value"); - std::cout << "SET " << key << ": " << value << "\n"; - std::cout << "GET " << key << ": " << result.toString() << "\n"; - - if( result.toString() != value ) + if( result.isError() ) { - std::cerr << "Invalid value from redis: " << result.toString() << std::endl; + std::cerr << "SET error: " << result.toString() << "\n"; return EXIT_FAILURE; } - return EXIT_SUCCESS; + result = redis.command("GET", "key"); + + if( result.isOk() ) + { + std::cout << "GET " << key << ": " << result.toString() << "\n"; + return EXIT_SUCCESS; + } + else + { + std::cerr << "GET error: " << result.toString() << "\n"; + return EXIT_FAILURE; + } } diff --git a/src/redisclient/impl/redisparser.cpp b/src/redisclient/impl/redisparser.cpp index 3bafdad..b71f026 100644 --- a/src/redisclient/impl/redisparser.cpp +++ b/src/redisclient/impl/redisparser.cpp @@ -195,7 +195,6 @@ std::pair RedisParser::parseChunk(const char * } break; case StringLF: - case ErrorLF: if( c == '\n') { state = Start; @@ -208,6 +207,20 @@ std::pair RedisParser::parseChunk(const char * return std::make_pair(i + 1, Error); } break; + case ErrorLF: + if( c == '\n') + { + state = Start; + RedisValue::ErrorTag tag; + valueStack.push(RedisValue(buf, tag)); + return std::make_pair(i + 1, Completed); + } + else + { + state = Start; + return std::make_pair(i + 1, Error); + } + break; case BulkSizeLF: if( c == '\n' ) { diff --git a/src/redisclient/impl/redisvalue.cpp b/src/redisclient/impl/redisvalue.cpp index 1c0f2e8..c8aaf1b 100644 --- a/src/redisclient/impl/redisvalue.cpp +++ b/src/redisclient/impl/redisvalue.cpp @@ -11,32 +11,37 @@ #include "../redisvalue.h" RedisValue::RedisValue() - : value(NullTag()) + : value(NullTag()), error(false) { } RedisValue::RedisValue(int i) - : value(i) + : value(i), error(false) { } RedisValue::RedisValue(const char *s) - : value( std::vector(s, s + strlen(s)) ) + : value( std::vector(s, s + strlen(s)) ), error(false) { } RedisValue::RedisValue(const std::string &s) - : value( std::vector(s.begin(), s.end()) ) + : value( std::vector(s.begin(), s.end()) ), error(false) { } RedisValue::RedisValue(const std::vector &buf) - : value(buf) + : value(buf), error(false) +{ +} + +RedisValue::RedisValue(const std::vector &buf, struct ErrorTag &) + : value(buf), error(true) { } RedisValue::RedisValue(const std::vector &array) - : value(array) + : value(array), error(false) { } @@ -63,7 +68,17 @@ int RedisValue::toInt() const std::string RedisValue::inspect() const { - if( isNull() ) + if( isError() ) + { + static std::string err = "error: "; + std::string result; + + result = err; + result += toString(); + + return result; + } + else if( isNull() ) { static std::string null = "(null)"; return null; @@ -101,6 +116,16 @@ std::string RedisValue::inspect() const } } +bool RedisValue::isOk() const +{ + return !isError(); +} + +bool RedisValue::isError() const +{ + return error; +} + bool RedisValue::isNull() const { return typeEq(); diff --git a/src/redisclient/redisvalue.h b/src/redisclient/redisvalue.h index 648ee29..efcf7e6 100644 --- a/src/redisclient/redisvalue.h +++ b/src/redisclient/redisvalue.h @@ -14,11 +14,14 @@ class RedisValue { public: + struct ErrorTag {}; + REDIS_CLIENT_DECL RedisValue(); REDIS_CLIENT_DECL RedisValue(int i); REDIS_CLIENT_DECL RedisValue(const char *s); REDIS_CLIENT_DECL RedisValue(const std::string &s); REDIS_CLIENT_DECL RedisValue(const std::vector &buf); + REDIS_CLIENT_DECL RedisValue(const std::vector &buf, struct ErrorTag &); REDIS_CLIENT_DECL RedisValue(const std::vector &array); // Return the value as a std::string if @@ -41,6 +44,12 @@ class RedisValue { // for dump content of the value. REDIS_CLIENT_DECL std::string inspect() const; + // Return true if value not a error + REDIS_CLIENT_DECL bool isOk() const; + // Return true if value is a error + REDIS_CLIENT_DECL bool isError() const; + + // Return true if this is a null. REDIS_CLIENT_DECL bool isNull() const; // Return true if type is an int @@ -71,6 +80,7 @@ class RedisValue { boost::variant, std::vector > value; + bool error; }; From 9e57c4689a7f09edfc09f7ca19cf7912c3c62690 Mon Sep 17 00:00:00 2001 From: Alex Nekipelov Date: Thu, 30 Apr 2015 16:04:59 +0300 Subject: [PATCH 19/21] tcp_nodelay for sync client --- examples/sync_set_get.cpp | 2 +- src/redisclient/impl/redissyncclient.cpp | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/examples/sync_set_get.cpp b/examples/sync_set_get.cpp index 4cb1892..660e776 100644 --- a/examples/sync_set_get.cpp +++ b/examples/sync_set_get.cpp @@ -34,7 +34,7 @@ int main(int, char **) if( result.isOk() ) { - std::cout << "GET " << key << ": " << result.toString() << "\n"; + std::cout << "GET: " << result.toString() << "\n"; return EXIT_SUCCESS; } else diff --git a/src/redisclient/impl/redissyncclient.cpp b/src/redisclient/impl/redissyncclient.cpp index 6f71973..c0b742f 100644 --- a/src/redisclient/impl/redissyncclient.cpp +++ b/src/redisclient/impl/redissyncclient.cpp @@ -26,7 +26,17 @@ bool RedisSyncClient::connect(const boost::asio::ip::tcp::endpoint &endpoint, { boost::system::error_code ec; - pimpl->socket.connect(endpoint, ec); + pimpl->socket.open(endpoint.protocol(), ec); + + if( !ec ) + { + pimpl->socket.set_option(boost::asio::ip::tcp::no_delay(true), ec); + + if( !ec ) + { + pimpl->socket.connect(endpoint, ec); + } + } if( !ec ) { From 064dbeda240695d29dc43fde34e80e9ef113bb1e Mon Sep 17 00:00:00 2001 From: Alex Nekipelov Date: Thu, 4 Jun 2015 18:40:16 +0300 Subject: [PATCH 20/21] Fix issue #11 --- README.md | 2 +- src/redisclient/impl/redissyncclient.cpp | 1 - src/redisclient/version.h | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8addb10..e0aeaaa 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ redisclient Build status: [![Build Status](https://travis-ci.org/nekipelov/redisclient.svg?branch=unstable)](https://travis-ci.org/nekipelov/redisclient) -Current version: 0.4.0 +Current version: 0.4.1 Boost.asio based Redis-client header-only library. Simple but powerfull. diff --git a/src/redisclient/impl/redissyncclient.cpp b/src/redisclient/impl/redissyncclient.cpp index c0b742f..9ded16a 100644 --- a/src/redisclient/impl/redissyncclient.cpp +++ b/src/redisclient/impl/redissyncclient.cpp @@ -41,7 +41,6 @@ bool RedisSyncClient::connect(const boost::asio::ip::tcp::endpoint &endpoint, if( !ec ) { pimpl->state = RedisClientImpl::Connected; - pimpl->processMessage(); return true; } else diff --git a/src/redisclient/version.h b/src/redisclient/version.h index bd692d0..bf623ce 100644 --- a/src/redisclient/version.h +++ b/src/redisclient/version.h @@ -6,6 +6,6 @@ #ifndef REDISCLIENT_VERSION_H #define REDISCLIENT_VERSION_H -#define REDIS_CLIENT_VERSION 400 // 0.4.0 +#define REDIS_CLIENT_VERSION 401 // 0.4.1 #endif // REDISCLIENT_VERSION_H From 8f7be0a55863246c4791f7b0b527a58c99729781 Mon Sep 17 00:00:00 2001 From: David Feurle Date: Wed, 18 Feb 2015 13:03:14 +0100 Subject: [PATCH 21/21] added project files --- .gitignore | 3 ++- examples/example1.pro | 13 +++++++++++++ examples/example2.pro | 13 +++++++++++++ examples/example3.pro | 13 +++++++++++++ examples/example4.pro | 13 +++++++++++++ examples/example5.pro | 13 +++++++++++++ examples/examples.pri | 2 ++ globals.pri | 8 ++++++++ redisclient.pro | 9 +++++++++ src/redisclient.pro | 26 ++++++++++++++++++++++++++ 10 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 examples/example1.pro create mode 100644 examples/example2.pro create mode 100644 examples/example3.pro create mode 100644 examples/example4.pro create mode 100644 examples/example5.pro create mode 100644 examples/examples.pri create mode 100644 globals.pri create mode 100644 redisclient.pro create mode 100644 src/redisclient.pro diff --git a/.gitignore b/.gitignore index 03139c9..fd13849 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.o *.so examples/example[1-4] -tests/parsertest \ No newline at end of file +tests/parsertest +/redisclient.pro.user diff --git a/examples/example1.pro b/examples/example1.pro new file mode 100644 index 0000000..fdbb889 --- /dev/null +++ b/examples/example1.pro @@ -0,0 +1,13 @@ +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle +CONFIG -= qt + +include(../globals.pri) +include(examples.pri) + +SOURCES += \ + example1.cpp + + + diff --git a/examples/example2.pro b/examples/example2.pro new file mode 100644 index 0000000..f97ed12 --- /dev/null +++ b/examples/example2.pro @@ -0,0 +1,13 @@ +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle +CONFIG -= qt + +include(../globals.pri) +include(examples.pri) + +SOURCES += \ + example2.cpp + + + diff --git a/examples/example3.pro b/examples/example3.pro new file mode 100644 index 0000000..64624ed --- /dev/null +++ b/examples/example3.pro @@ -0,0 +1,13 @@ +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle +CONFIG -= qt + +include(../globals.pri) +include(examples.pri) + +SOURCES += \ + example3.cpp + + + diff --git a/examples/example4.pro b/examples/example4.pro new file mode 100644 index 0000000..3a2de56 --- /dev/null +++ b/examples/example4.pro @@ -0,0 +1,13 @@ +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle +CONFIG -= qt + +include(../globals.pri) +include(examples.pri) + +SOURCES += \ + example4.cpp + + + diff --git a/examples/example5.pro b/examples/example5.pro new file mode 100644 index 0000000..09f857d --- /dev/null +++ b/examples/example5.pro @@ -0,0 +1,13 @@ +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle +CONFIG -= qt + +include(../globals.pri) +include(examples.pri) + +SOURCES += \ + example5.cpp + + + diff --git a/examples/examples.pri b/examples/examples.pri new file mode 100644 index 0000000..cc29ea4 --- /dev/null +++ b/examples/examples.pri @@ -0,0 +1,2 @@ +DEPENDPATH += ../src +INCLUDEPATH += ../src diff --git a/globals.pri b/globals.pri new file mode 100644 index 0000000..a28a398 --- /dev/null +++ b/globals.pri @@ -0,0 +1,8 @@ +CONFIG += c++11 + +win32:LIBS += -Lc:/local/boost_1_56_0/lib32-msvc-12.0/ + +win32:INCLUDEPATH += c:/local/boost_1_56_0 +win32:DEPENDPATH += c:/local/boost_1_56_0 + +unix:LIBS += -lboost_system diff --git a/redisclient.pro b/redisclient.pro new file mode 100644 index 0000000..90c5e6e --- /dev/null +++ b/redisclient.pro @@ -0,0 +1,9 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + examples/example1.pro \ + examples/example2.pro \ + examples/example3.pro \ + examples/example4.pro \ + examples/example5.pro \ + src/redisclient.pro diff --git a/src/redisclient.pro b/src/redisclient.pro new file mode 100644 index 0000000..13311f6 --- /dev/null +++ b/src/redisclient.pro @@ -0,0 +1,26 @@ +QT -= core gui + +TARGET = redisclient +TEMPLATE = lib +CONFIG += staticlib + +include(../globals.pri) + + +HEADERS += \ + redisclient/config.h \ + redisclient/redisasyncclient.h \ + redisclient/redisbuffer.h \ + redisclient/redisclient.h \ + redisclient/redisparser.h \ + redisclient/redissyncclient.h \ + redisclient/redisvalue.h \ + redisclient/version.h + +SOURCES += \ + redisclient/impl/redisasyncclient.cpp \ + redisclient/impl/redisclientimpl.cpp \ + redisclient/impl/redisparser.cpp \ + redisclient/impl/redissyncclient.cpp \ + redisclient/impl/redisvalue.cpp +