// ---------------------------------------------------------------------- // File: ResponseBuilder.cc // Author: Georgios Bitzes - CERN // ---------------------------------------------------------------------- /************************************************************************ * qclient - A simple redis C++ client with support for redirects * * Copyright (C) 2016 CERN/Switzerland * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* ************************************************************************/ #include "qclient/ResponseBuilder.hh" #include "qclient/QClient.hh" #include "reader/reader.hh" #include #define SSTR(message) static_cast(std::ostringstream().flush() << message).str() namespace qclient { ResponseBuilder::ResponseBuilder() { restart(); } void ResponseBuilder::restart() { reader.reset(redisReaderCreate()); } void ResponseBuilder::feed(const char* buff, size_t len) { if(len > 0) { redisReaderFeed(reader.get(), buff, len); } } void ResponseBuilder::feed(const std::string &str) { feed(str.c_str(), str.size()); } void ResponseBuilder::Deleter::operator()(redisReader *reader) { redisReaderFree(reader); } ResponseBuilder::Status ResponseBuilder::pull(redisReplyPtr &out) { void* reply = nullptr; if(redisReaderGetReply(reader.get(), &reply) == REDIS_ERR) { return Status::kProtocolError; } if(!reply) { return Status::kIncomplete; } out = redisReplyPtr(redisReplyPtr((redisReply*) reply, freeReplyObject)); return Status::kOk; } redisReplyPtr ResponseBuilder::makeInt(int val) { ResponseBuilder builder; builder.feed(SSTR(":" << val << "\r\n")); redisReplyPtr ans; builder.pull(ans); return ans; } redisReplyPtr ResponseBuilder::makeErr(const std::string &msg) { ResponseBuilder builder; builder.feed(SSTR("-" << msg << "\r\n")); redisReplyPtr ans; builder.pull(ans); return ans; } redisReplyPtr ResponseBuilder::makeStr(const std::string &msg) { ResponseBuilder builder; builder.feed(SSTR("$" << msg.size() << "\r\n" << msg << "\r\n")); redisReplyPtr ans; builder.pull(ans); return ans; } redisReplyPtr ResponseBuilder::makePushArray(const std::vector &msg) { return makeStringArray(msg, '>'); } redisReplyPtr ResponseBuilder::makeStringArray(const std::vector &msg, char prefix) { ResponseBuilder builder; builder.feed(SSTR(prefix << msg.size() << "\r\n")); for(size_t i = 0; i < msg.size(); i++) { builder.feed(SSTR("$" << msg[i].size() << "\r\n" << msg[i] << "\r\n")); } redisReplyPtr ans; builder.pull(ans); return ans; } redisReplyPtr ResponseBuilder::makePushArr(const std::string &str1, const std::string &str2, const std::string &str3, int num) { ResponseBuilder builder; builder.feed(">4\r\n"); builder.feed(SSTR("$" << str1.size() << "\r\n" << str1 << "\r\n")); builder.feed(SSTR("$" << str2.size() << "\r\n" << str2 << "\r\n")); builder.feed(SSTR("$" << str3.size() << "\r\n" << str3 << "\r\n")); builder.feed(SSTR(":" << num << "\r\n")); redisReplyPtr ans; builder.pull(ans); return ans; } redisReplyPtr ResponseBuilder::makeArr(const std::string &str1, const std::string &str2, int num) { ResponseBuilder builder; builder.feed("*3\r\n"); builder.feed(SSTR("$" << str1.size() << "\r\n" << str1 << "\r\n")); builder.feed(SSTR("$" << str2.size() << "\r\n" << str2 << "\r\n")); builder.feed(SSTR(":" << num << "\r\n")); redisReplyPtr ans; builder.pull(ans); return ans; } redisReplyPtr ResponseBuilder::makeStatus(const std::string &msg) { ResponseBuilder builder; builder.feed("+"); builder.feed(msg); builder.feed("\r\n"); redisReplyPtr ans; builder.pull(ans); return ans; } redisReplyPtr ResponseBuilder::parseRedisEncodedString(const std::string &str) { ResponseBuilder builder; builder.feed(str); redisReplyPtr ans; builder.pull(ans); return ans; } // Convenience function to quickly parse a redis-encoded string into redis-cli-like // description std::string ResponseBuilder::parseAndDescribeRedisEncodedString(const std::string &str) { return qclient::describeRedisReply(parseRedisEncodedString(str)); } std::string describeRedisReply(const std::string &str) { return ResponseBuilder::parseAndDescribeRedisEncodedString(str); } }