#pragma once
#include
#include
#include
#include
namespace PBLIB
{
namespace Redis
{
enum class PB_HIREDISUTILITY_EVENT
{
Connect = 100,
TryConnect,
DisConnect
};
class hiredisUtility
{
public:
typedef std::function EventHandler;
hiredisUtility();
~hiredisUtility();
void Start();
void Connect(int millisecond);
void Disonnect();
bool Ping();
bool CmdGetString(std::string &restr, const char *format, ...);
bool CmdGetInteger(long long &val, const char *format, ...);
bool CmdAndEuqalString(const char * equalval, const char *format, ...);
//Key,Value
void Get(const char *key, std::string &restr);
bool Set(const char *key, const std::string &valstr);
bool Set(const char *key, char * buff, int size);
//List
long long LPush(const char * listId, char * buff, int size);
long long LPush(const char * listId, const std::string &valstr);
bool LPop(const char * listId, std::string &valstr);
int LLen(const char * listId);
bool LRange(const char * listId, int startingFrom, int endingAt,std::vector &vec);
bool GetList(const char * listId, std::vector &vec);
EventHandler evenhandler;
std::mutex m_Cmdmutex;
private:
void* Cmd(const char *format, ...);
bool IsAutoReconnect;
char m_ip[15];
int m_port;
void * m_Context;
std::string m_errorDetail;
};
}
}
#include "hiredishelper.h"
#include
#include
#include
#include
#include
#include "WinSock2.h"
#include "../../external/hiredis-win32-master/include/hiredis.h"
#pragma comment(lib, "ws2_32.lib")
namespace PBLIB
{
namespace Redis
{
#define REDIS_REPLY_STR_OK "OK"
hiredisUtility::hiredisUtility() :m_port(6379)
{
strcpy(m_ip, "127.0.0.1");
m_Context = nullptr;
evenhandler = nullptr;
//main2();
}
hiredisUtility::~hiredisUtility()
{
IsAutoReconnect = false;//停止自动重连线程
}
//http://blog.csdn.net/gdutliuyun827/article/details/44339007
bool hiredisUtility::Ping()
{
return CmdAndEuqalString("PONG", "PING");
}
//万能方案备用
void* hiredisUtility::Cmd(const char *format, ...)
{
if (m_Context == nullptr) return NULL;
redisContext *c = (redisContext*)m_Context;
va_list ap;
void *reply = NULL;
va_start(ap, format);
reply = redisvCommand(c, format, ap);
va_end(ap);
if (!c->err)
{
return reply;
}
return NULL;
}
bool hiredisUtility::CmdGetString(std::string &restr, const char *format, ...)
{
if (m_Context == nullptr) return false;
std::lock_guard locker(m_Cmdmutex);
redisContext *c = (redisContext*)m_Context;
va_list ap;
void *reply = NULL;
va_start(ap, format);
reply = redisvCommand(c, format, ap);
va_end(ap);
if (!c->err)
{
bool IsErroring = false;
bool flag = false;
redisReply* r = (redisReply*)reply;
if (r->type == REDIS_REPLY_STRING)
{
restr = r->str;
flag = true;
}
if (r->type == REDIS_REPLY_ERROR)
{
IsErroring = true;
m_errorDetail = r->str;
}
freeReplyObject(r);
if (IsErroring) throw std::exception(m_errorDetail.data());//直接丢错
return flag;
}
return false;
}
bool hiredisUtility::CmdGetInteger(long long &val, const char *format, ...)
{
if (m_Context == nullptr) return false;
std::lock_guard locker(m_Cmdmutex);
redisContext *c = (redisContext*)m_Context;
va_list ap;
void *reply = NULL;
va_start(ap, format);
reply = redisvCommand(c, format, ap);
va_end(ap);
if (!c->err)
{
bool IsErroring = false;
bool flag = false;
redisReply* r = (redisReply*)reply;
if (r->type == REDIS_REPLY_INTEGER)
{
val = r->integer;
flag = true;
}
if (r->type == REDIS_REPLY_ERROR)
{
IsErroring = true;
m_errorDetail = r->str;
}
freeReplyObject(r);
if (IsErroring) throw std::exception(m_errorDetail.data());//直接丢错
return flag;
}
return false;
}
bool hiredisUtility::CmdAndEuqalString(const char * equalval, const char *format, ...)
{
if (m_Context == nullptr) return false;
std::lock_guard locker(m_Cmdmutex);
redisContext *c = (redisContext*)m_Context;
va_list ap;
void *reply = NULL;
va_start(ap, format);
reply = redisvCommand(c, format, ap);
va_end(ap);
if (!c->err)
{
bool IsErroring = false;
bool flag = false;
redisReply* r = (redisReply*)reply;
if (r->str != NULL)
flag = strcmp(equalval, r->str) == 0;//如果返回是str
if (r->type == REDIS_REPLY_ERROR)
{
IsErroring = true;
m_errorDetail = r->str;
}
freeReplyObject(r);
if (IsErroring) throw std::exception(m_errorDetail.data());//直接丢错
return flag;
}
return false;
}
void hiredisUtility::Get(const char *key, std::string &restr)
{
CmdGetString(restr, "get %s", key);
}
bool hiredisUtility::Set(const char *key, const std::string &valstr)
{
return CmdAndEuqalString(REDIS_REPLY_STR_OK, "set %b %b", key, strlen(key), valstr.data(), valstr.size());
}
bool hiredisUtility::Set(const char *key, char * buff, int size){
return CmdAndEuqalString(REDIS_REPLY_STR_OK, "set %b %b", key, strlen(key), buff, size);
}
long long hiredisUtility::LPush(const char * listId, char * buff, int size)
{
long long res = 0;
CmdGetInteger(res, "LPush %b %b", listId, strlen(listId), buff, size);
return res;
}
long long hiredisUtility::LPush(const char * listId, const std::string &valstr){
long long res = 0;
CmdGetInteger(res, "LPush %b %b", listId, strlen(listId), valstr.data(), valstr.size());
return res;
}
bool hiredisUtility::LPop(const char * listId, std::string &valstr)
{
return CmdGetString(valstr, "LPop %s", listId);
}
void hiredisUtility::Connect(int millisecond)
{
if (m_Context != nullptr) return;
int tv_sec = millisecond / 1000;
int millisec = millisecond % 1000;
long tv_usec = millisec * 1000;
struct timeval timeout;
timeout.tv_sec = tv_sec;
timeout.tv_usec = tv_usec;
redisContext *c;
c = redisConnectWithTimeout(m_ip, m_port, timeout);
if (c != NULL && c->err)
{
redisFree(c);
return;
}
m_Context = c;
if (m_Context != nullptr)
if (evenhandler != nullptr)
evenhandler("Redis连接上", PB_HIREDISUTILITY_EVENT::Connect, NULL);
}
int hiredisUtility::LLen(const char * listId)
{
long long res = 0;
CmdGetInteger(res, "LLen %b", listId, strlen(listId));
return res;
}
bool hiredisUtility::LRange(const char * listId, int startingFrom, int endingAt, std::vector &vec)
{
std::lock_guard locker(m_Cmdmutex);
void *reply = Cmd("LRange %s %d %d", listId, startingFrom, endingAt);
if (reply == NULL) return false;
bool IsErroring = false;
bool flag = false;
redisReply* r = (redisReply*)reply;
if (r->type == REDIS_REPLY_ERROR)
{
IsErroring = true;
m_errorDetail = r->str;
}
if (r->type == REDIS_REPLY_ARRAY)
{
flag = true;
for (int j = 0; j < r->elements; j++)
{
std::string str = r->element[j]->str;
vec.push_back(str);
}
}
freeReplyObject(r);
if (IsErroring) throw std::exception(m_errorDetail.data());//直接丢错
return flag;
}
bool hiredisUtility::GetList(const char * listId, std::vector &vec){
int len = LLen(listId);
return LRange(listId, 0, len - 1, vec);
}
void hiredisUtility::Start()
{
IsAutoReconnect = true;
std::thread th([this](){
while (IsAutoReconnect)
{
std::chrono::milliseconds timespan(1000);
std::this_thread::sleep_for(timespan);
if (Ping() == false)
{
Disonnect();
evenhandler("Redis尝试连接", PB_HIREDISUTILITY_EVENT::TryConnect, NULL);
Connect(1000);
}
}
Disonnect();
});
th.detach();
}
void hiredisUtility::Disonnect()
{
if (m_Context == nullptr) return;
redisContext *c = (redisContext*)m_Context;
if (c != NULL)
{
redisFree(c);
m_Context = nullptr;
evenhandler("Redis断开了", PB_HIREDISUTILITY_EVENT::Connect, NULL);
}
}
//void redisFree(redisContext *c);
}
}