调用函数:
int32_t seasonId = 0;{pRedisSession->commandF("HGET {} season_id", strArenaConfig);RedisReply r(pRedisSession->getReply());if (r.isString()){auto buffer = r.getString();seasonId = std::atoi(buffer.c_str());}}
头文件:
#pragma once#include "prerequisites.h"
#include <hiredis.h>class RedisReply
{
public:explicit RedisReply(redisReply* r);~RedisReply() = default;void copy(redisReply* r);int getType() const { return m_type; }bool isNil() { return m_type == REDIS_REPLY_NIL; }bool isError() { return m_type == REDIS_REPLY_ERROR; }bool isStatus() { return m_type == REDIS_REPLY_STATUS; }bool isString() { return m_type == REDIS_REPLY_STRING; }bool isInteger() { return m_type == REDIS_REPLY_INTEGER; }bool isArray() { return m_type == REDIS_REPLY_ARRAY; }int64_t getInteger() { return m_integer; }std::string getString() { return m_string; }int sizeElement() { return (int)m_element.size(); }RedisReply* getElement(int index);private:int m_type;int64_t m_integer;std::string m_string;std::vector<RedisReply> m_element;
};class RedisSession : private boost::noncopyable
{
public:RedisSession();virtual ~RedisSession();virtual void initialize(const std::string& hostName, uint16_t port, int dbnum, const std::string& password, float connectimeout);virtual bool connect();bool isValid();void close();void freeReply();void command(const char* cmd);void commandArgv(int argc, const char** argv, const size_t* argvlen);template<typename... Args>void commandF(std::string_view fmt, Args&&... args){try{std::string strCmd = fmt::format(fmt, std::forward<Args>(args)...);command(strCmd.c_str());}catch (const std::exception& e){assert(false);printf("commandF err:%s ~~ %s\n", e.what(), fmt.data());}}redisReply* getReply(){return m_pReply;}protected:std::string m_hostName;uint16_t m_port;int m_dbnum;std::string m_password;float m_connectimeout;redisContext* m_pContext;redisReply* m_pReply;
};
源文件:
#include "RedisSession.h"
#include "LoggerManager.h"RedisReply::RedisReply(redisReply* r): m_type(REDIS_REPLY_NIL), m_integer(0)
{copy(r);
}void RedisReply::copy(redisReply* r)
{if (nullptr == r){m_type = REDIS_REPLY_NIL;return;}m_type = r->type;switch (m_type){case REDIS_REPLY_NIL:/* Nothing... */break;case REDIS_REPLY_ERROR:case REDIS_REPLY_STATUS:case REDIS_REPLY_STRING:m_string.assign(r->str, r->len);break;case REDIS_REPLY_INTEGER:m_integer = r->integer;break;case REDIS_REPLY_ARRAY:m_element.clear();for (size_t i = 0; i < r->elements; i++){m_element.push_back(RedisReply(r->element[i]));}break;default:{m_type = REDIS_REPLY_ERROR;m_string = fmt::format("Unknown reply type: {}", r->type);}break;}
}RedisReply* RedisReply::getElement(int index)
{int num = m_element.size();if ((size_t)index >= m_element.size())return nullptr;return &m_element[index];
}//RedisSession::RedisSession(): m_port(0), m_dbnum(0), m_connectimeout(1.5f), m_pContext(nullptr), m_pReply(nullptr)
{
}RedisSession::~RedisSession()
{close();
}void RedisSession::initialize(const std::string& hostName, uint16_t port, int dbnum, const std::string& password, float connectimeout)
{m_hostName = hostName;m_port = (port == 0 ? 6379 : port); // 默认端口m_dbnum = dbnum;m_password = password;m_connectimeout = connectimeout;
}void RedisSession::close()
{LOG_INFO(redis, "redis(host={}, port={}, dbnum={}) close", m_hostName, m_port, m_dbnum);freeReply();if (m_pContext){redisFree(m_pContext);m_pContext = nullptr;}
}void RedisSession::freeReply()
{if (m_pReply){freeReplyObject(m_pReply);m_pReply = nullptr;}
}bool RedisSession::isValid()
{return m_pContext;
}bool RedisSession::connect()
{struct timeval tv;tv.tv_sec = static_cast<long>(m_connectimeout);tv.tv_usec = static_cast<long>(m_connectimeout * 1000000) % 1000000;m_pContext = redisConnectWithTimeout(m_hostName.c_str(), m_port, tv);if (!m_pContext){LOG_ERROR(redis, "redis(host={}, port={}, dbnum={}) connect failed", m_hostName, m_port, m_dbnum);return false;}if (m_pContext->err){LOG_ERROR(redis, "redis(host={}, port={}, dbnum={}) connect failed({}):{}", m_hostName, m_port, m_dbnum, m_pContext->err, m_pContext->errstr);redisFree(m_pContext);m_pContext = nullptr;return false;}if (!m_password.empty()){m_pReply = (redisReply*)redisCommand(m_pContext, "AUTH %s", m_password.c_str());if (m_pReply){bool result = true;if (m_pReply->type == REDIS_REPLY_ERROR) result = false;freeReplyObject(m_pReply);m_pReply = nullptr;if (!result){LOG_ERROR(redis, "redis(host={}, port={}, dbnum={}) auth failed", m_hostName, m_port, m_dbnum);return false;}}}if (m_dbnum != 0){m_pReply = (redisReply*)redisCommand(m_pContext, "SELECT %d", m_dbnum);if (m_pReply){bool result = true;if (m_pReply->type == REDIS_REPLY_ERROR) result = false;freeReplyObject(m_pReply);m_pReply = nullptr;if (!result){LOG_ERROR(redis, "redis(host={}, port={}, dbnum={}) select dbnum failed", m_hostName, m_port, m_dbnum);return false;}}}m_pReply = (redisReply*)redisCommand(m_pContext, "PING");if (m_pReply){bool result = true;if (m_pReply->type == REDIS_REPLY_ERROR) result = false;freeReplyObject(m_pReply);m_pReply = nullptr;if (!result){LOG_ERROR(redis, "redis(host={}, port={}, dbnum={}) first ping failed", m_hostName, m_port, m_dbnum);return false;}}LOG_INFO(redis, "redis(host={}, port={}, dbnum={}) connect ok", m_hostName, m_port, m_dbnum);return true;
}void RedisSession::command(const char* cmd)
{if (m_pContext){freeReply();m_pReply = (redisReply*)redisCommand(m_pContext, cmd);}if (m_pReply == nullptr || m_pContext == nullptr){// 连接断开立即重连一次close();if (!connect()){return;}m_pReply = (redisReply*)redisCommand(m_pContext, cmd);}
}void RedisSession::commandArgv(int argc, const char** argv, const size_t* argvlen)
{assert(argc > 0);if (m_pContext){freeReply();m_pReply = (redisReply*)redisCommandArgv(m_pContext, argc, argv, argvlen);}if (m_pReply == nullptr || m_pContext == nullptr){// 连接断开立即重连一次close();if (!connect()){return;}m_pReply = (redisReply*)redisCommandArgv(m_pContext, argc, argv, argvlen);}
}