coyote/hiredis_wrapper.cpp

154 lines
4.9 KiB
C++

#include "config.h"
#include "hiredis_wrapper.h"
std::optional<Redis> redis;
Redis::Redis(const std::string& address, int port) {
this->_context = redisConnect(address.c_str(), port);
if (!this->_context) {
throw std::bad_alloc();
}
if (this->_context->err) {
RedisException e(this->_context->errstr);
redisFree(this->_context);
throw e;
}
}
Redis::Redis(const std::string& unix) {
this->_context = redisConnectUnix(unix.c_str());
if (!this->_context) {
throw std::bad_alloc();
}
if (this->_context->err) {
RedisException e(this->_context->errstr);
redisFree(this->_context);
throw e;
}
}
Redis::~Redis() {
redisFree(this->_context);
}
void Redis::auth(const std::string& username, const std::string& password) {
RedisReply reply = this->command("AUTH %s %s", username.c_str(), password.c_str());
if (reply->type == REDIS_REPLY_STATUS) {
// good :D
} else {
throw std::runtime_error("AUTH gave an unexpected return type");
}
}
void Redis::auth(const std::string& password) {
RedisReply reply = this->command("AUTH %s", password.c_str());
if (reply->type == REDIS_REPLY_STATUS) {
// good :D
} else {
throw std::runtime_error("AUTH gave an unexpected return type");
}
}
time_t Redis::ttl(const std::string& key) {
RedisReply reply = this->command("TTL %s", key.c_str());
if (reply->type == REDIS_REPLY_INTEGER) {
return reply->integer;
} else {
throw std::runtime_error("TTL gave an unexpected return type");
}
}
bool Redis::expire(const std::string& key, time_t expiry) {
RedisReply reply = this->command("EXPIRE %s %d", key.c_str(), expiry);
if (reply->type == REDIS_REPLY_INTEGER) {
return reply->integer == 1;
} else {
throw std::runtime_error("EXPIRE gave an unexpected return type");
}
}
bool Redis::expire_nx(const std::string& key, time_t expiry) {
if (this->_fake_expire_nx) {
time_t current_expiry = this->ttl(key);
if (current_expiry < 0) {
return this->expire(key, expiry);
}
return false;
}
RedisReply reply(nullptr, freeReplyObject);
try{
reply = this->command("EXPIRE %s %d NX", key.c_str(), expiry);
} catch (const RedisException& e) {
if (e.error == "ERR wrong number of arguments for 'expire' command") {
this->_fake_expire_nx = true;
return this->expire_nx(key, expiry);
}
throw;
}
if (reply->type == REDIS_REPLY_INTEGER) {
return reply->integer == 1;
} else {
throw std::runtime_error("EXPIRE NX gave an unexpected return type");
}
}
std::optional<std::string> Redis::get(const std::string& key) {
RedisReply reply = this->command("GET %s", key.c_str());
if (reply->type == REDIS_REPLY_STRING) {
return std::string(reply->str, reply->len);
} else if (reply->type == REDIS_REPLY_NIL) {
return std::nullopt;
} else {
throw std::runtime_error("GET gave an unexpected return type");
}
}
void Redis::set(const std::string& key, const std::string& value, time_t expiry) {
RedisReply reply = this->command("SET %s %s EX %d", key.c_str(), value.c_str(), expiry);
if (reply->type == REDIS_REPLY_STATUS) {
// good :D
} else {
throw std::runtime_error("SET gave an unexpected return type");
}
}
std::optional<std::string> Redis::hget(const std::string& key, const std::string& field) {
RedisReply reply = this->command("HGET %s %s", key.c_str(), field.c_str());
if (reply->type == REDIS_REPLY_STRING) {
return std::string(reply->str, reply->len);
} else if (reply->type == REDIS_REPLY_NIL) {
return std::nullopt;
} else {
throw std::runtime_error("HGET gave an unexpected return type");
}
}
void Redis::hset(const std::string& key, const std::string& field, const std::string& value) {
RedisReply reply = this->command("HSET %s %s %s", key.c_str(), field.c_str(), value.c_str());
if (reply->type == REDIS_REPLY_INTEGER) {
// good :D
} else {
throw std::runtime_error("SET gave an unexpected return type");
}
}
void init_redis() {
if (!config.redis_config) {
return;
}
if (const IPConnection* ip = std::get_if<IPConnection>(&config.redis_config->connection_method)) {
redis.emplace(ip->address, ip->port);
} else if (const UnixConnection* unix = std::get_if<UnixConnection>(&config.redis_config->connection_method)) {
redis.emplace(unix->unix);
} else {
__builtin_unreachable();
}
if (config.redis_config->username && config.redis_config->password) {
redis->auth(*config.redis_config->username, *config.redis_config->password);
} else if (config.redis_config->password) {
redis->auth(*config.redis_config->password);
}
}