mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-02-15 23:41:57 +00:00
159 lines
4.0 KiB
C++
159 lines
4.0 KiB
C++
/**************************************************************************
|
|
Copyright (c) 2017 sewenew
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*************************************************************************/
|
|
|
|
#include "reply.h"
|
|
#include <cstdlib>
|
|
#include <stdexcept>
|
|
|
|
namespace sw {
|
|
|
|
namespace redis {
|
|
|
|
namespace reply {
|
|
|
|
std::string to_status(redisReply &reply) {
|
|
if (!reply::is_status(reply)) {
|
|
throw ProtoError("Expect STATUS reply");
|
|
}
|
|
|
|
if (reply.str == nullptr) {
|
|
throw ProtoError("A null status reply");
|
|
}
|
|
|
|
// Old version hiredis' *redisReply::len* is of type int.
|
|
// So we CANNOT have something like: *return {reply.str, reply.len}*.
|
|
return std::string(reply.str, reply.len);
|
|
}
|
|
|
|
std::string parse(ParseTag<std::string>, redisReply &reply) {
|
|
if (!reply::is_string(reply) && !reply::is_status(reply)) {
|
|
throw ProtoError("Expect STRING reply");
|
|
}
|
|
|
|
if (reply.str == nullptr) {
|
|
throw ProtoError("A null string reply");
|
|
}
|
|
|
|
// Old version hiredis' *redisReply::len* is of type int.
|
|
// So we CANNOT have something like: *return {reply.str, reply.len}*.
|
|
return std::string(reply.str, reply.len);
|
|
}
|
|
|
|
long long parse(ParseTag<long long>, redisReply &reply) {
|
|
if (!reply::is_integer(reply)) {
|
|
throw ProtoError("Expect INTEGER reply");
|
|
}
|
|
|
|
return reply.integer;
|
|
}
|
|
|
|
double parse(ParseTag<double>, redisReply &reply) {
|
|
try {
|
|
return std::stod(parse<std::string>(reply));
|
|
} catch (const std::invalid_argument &) {
|
|
throw ProtoError("not a double reply");
|
|
} catch (const std::out_of_range &) {
|
|
throw ProtoError("double reply out of range");
|
|
}
|
|
}
|
|
|
|
bool parse(ParseTag<bool>, redisReply &reply) {
|
|
auto ret = parse<long long>(reply);
|
|
|
|
if (ret == 1) {
|
|
return true;
|
|
} else if (ret == 0) {
|
|
return false;
|
|
} else {
|
|
throw ProtoError("Invalid bool reply: " + std::to_string(ret));
|
|
}
|
|
}
|
|
|
|
void parse(ParseTag<void>, redisReply &reply) {
|
|
if (!reply::is_status(reply)) {
|
|
throw ProtoError("Expect STATUS reply");
|
|
}
|
|
|
|
if (reply.str == nullptr) {
|
|
throw ProtoError("A null status reply");
|
|
}
|
|
|
|
static const std::string OK = "OK";
|
|
|
|
// Old version hiredis' *redisReply::len* is of type int.
|
|
// So we have to cast it to an unsigned int.
|
|
if (static_cast<std::size_t>(reply.len) != OK.size()
|
|
|| OK.compare(0, OK.size(), reply.str, reply.len) != 0) {
|
|
throw ProtoError("NOT ok status reply: " + reply::to_status(reply));
|
|
}
|
|
}
|
|
|
|
void rewrite_set_reply(redisReply &reply) {
|
|
if (is_nil(reply)) {
|
|
// Failed to set, and make it a FALSE reply.
|
|
reply.type = REDIS_REPLY_INTEGER;
|
|
reply.integer = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
// Check if it's a "OK" status reply.
|
|
reply::parse<void>(reply);
|
|
|
|
assert(is_status(reply) && reply.str != nullptr);
|
|
|
|
free(reply.str);
|
|
|
|
// Make it a TRUE reply.
|
|
reply.type = REDIS_REPLY_INTEGER;
|
|
reply.integer = 1;
|
|
}
|
|
|
|
void rewrite_empty_array_reply(redisReply &reply) {
|
|
if (is_array(reply) && reply.elements == 0) {
|
|
// Make it a nil reply.
|
|
reply.type = REDIS_REPLY_NIL;
|
|
}
|
|
}
|
|
|
|
namespace detail {
|
|
|
|
bool is_flat_array(redisReply &reply) {
|
|
assert(reply::is_array(reply));
|
|
|
|
// Empty array reply.
|
|
if (reply.element == nullptr || reply.elements == 0) {
|
|
return false;
|
|
}
|
|
|
|
auto *sub_reply = reply.element[0];
|
|
|
|
// Null element.
|
|
if (sub_reply == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
return !reply::is_array(*sub_reply);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|