Commit c6dbba89b067ac3e6fcf691f3c8a856ac3ef1b5c
1 parent
3b431e0e
Binary value support for last word in command
Implemented limited but useful binary data support without breaking the API. If the last character of the command is a ", look for the first ", and everything in between the quotes treat as binary data. Takes care of setting a key with a binary value. Not useful if there need to be multiple binary entries in one command, or for binary keys. Also need to be careful if the last character of the value actually needs to be a quote, in which case we need to quote the value.
Showing
5 changed files
with
76 additions
and
5 deletions
CMakeLists.txt
| @@ -84,4 +84,7 @@ if (examples) | @@ -84,4 +84,7 @@ if (examples) | ||
| 84 | add_executable(multi_client examples/multi-client.cpp ${SRC_ALL}) | 84 | add_executable(multi_client examples/multi-client.cpp ${SRC_ALL}) |
| 85 | target_link_libraries(multi_client ${LIB_REDIS}) | 85 | target_link_libraries(multi_client ${LIB_REDIS}) |
| 86 | 86 | ||
| 87 | + add_executable(binary_data examples/binary_data.cpp ${SRC_ALL}) | ||
| 88 | + target_link_libraries(binary_data ${LIB_REDIS}) | ||
| 89 | + | ||
| 87 | endif() | 90 | endif() |
README.md
examples/binary_data.cpp
0 → 100644
| 1 | +/** | ||
| 2 | +* Basic use of Redox to set and get binary data. | ||
| 3 | +*/ | ||
| 4 | + | ||
| 5 | +#include <iostream> | ||
| 6 | +#include <algorithm> | ||
| 7 | +#include <random> | ||
| 8 | +#include "../src/redox.hpp" | ||
| 9 | + | ||
| 10 | +using namespace std; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | +* Random string generator. | ||
| 14 | +*/ | ||
| 15 | +std::string random_string(size_t length) { | ||
| 16 | + std::string str(length, 0); | ||
| 17 | + std::generate_n(str.begin(), length, []{ return (unsigned char)rand(); }); | ||
| 18 | + return str; | ||
| 19 | +} | ||
| 20 | + | ||
| 21 | +int main(int argc, char* argv[]) { | ||
| 22 | + | ||
| 23 | + redox::Redox rdx = {"localhost", 6379}; // Initialize Redox | ||
| 24 | + if(!rdx.start()) return 1; // Start the event loop | ||
| 25 | + | ||
| 26 | + rdx.del("binary"); | ||
| 27 | + | ||
| 28 | + string binary_data = random_string(10000); | ||
| 29 | + | ||
| 30 | + auto c = rdx.command_blocking<string>("SET binary \"" + binary_data + "\""); | ||
| 31 | + if(c->ok()) cout << "Reply: " << c->reply() << endl; | ||
| 32 | + else cerr << "Failed to set key! Status: " << c->status() << endl; | ||
| 33 | + c->free(); | ||
| 34 | + | ||
| 35 | + c = rdx.command_blocking<string>("GET binary"); | ||
| 36 | + if(c->ok()) { | ||
| 37 | + if(c->reply() == binary_data) cout << "Binary data matches!" << endl; | ||
| 38 | + else cerr << "Binary data differs!" << endl; | ||
| 39 | + } | ||
| 40 | + else cerr << "Failed to get key! Status: " << c->status() << endl; | ||
| 41 | + c->free(); | ||
| 42 | + | ||
| 43 | + rdx.stop(); // Shut down the event loop | ||
| 44 | +} |
src/command.cpp
| @@ -46,7 +46,7 @@ void Command<std::string>::invoke_callback() { | @@ -46,7 +46,7 @@ void Command<std::string>::invoke_callback() { | ||
| 46 | invoke_error(REDOX_WRONG_TYPE); | 46 | invoke_error(REDOX_WRONG_TYPE); |
| 47 | 47 | ||
| 48 | } else { | 48 | } else { |
| 49 | - std::string s = reply_obj->str; | 49 | + std::string s(reply_obj->str, reply_obj->len); |
| 50 | invoke(s); | 50 | invoke(s); |
| 51 | } | 51 | } |
| 52 | } | 52 | } |
| @@ -129,7 +129,7 @@ void Command<std::vector<std::string>>::invoke_callback() { | @@ -129,7 +129,7 @@ void Command<std::vector<std::string>>::invoke_callback() { | ||
| 129 | std::cerr << "[ERROR] " << cmd << ": Received non-array reply." << std::endl; | 129 | std::cerr << "[ERROR] " << cmd << ": Received non-array reply." << std::endl; |
| 130 | invoke_error(REDOX_WRONG_TYPE); | 130 | invoke_error(REDOX_WRONG_TYPE); |
| 131 | } | 131 | } |
| 132 | - v.push_back(r->str); | 132 | + v.emplace_back(r->str, r->len); |
| 133 | } | 133 | } |
| 134 | invoke(v); | 134 | invoke(v); |
| 135 | } | 135 | } |
| @@ -153,7 +153,7 @@ void Command<std::unordered_set<std::string>>::invoke_callback() { | @@ -153,7 +153,7 @@ void Command<std::unordered_set<std::string>>::invoke_callback() { | ||
| 153 | std::cerr << "[ERROR] " << cmd << ": Received non-array reply." << std::endl; | 153 | std::cerr << "[ERROR] " << cmd << ": Received non-array reply." << std::endl; |
| 154 | invoke_error(REDOX_WRONG_TYPE); | 154 | invoke_error(REDOX_WRONG_TYPE); |
| 155 | } | 155 | } |
| 156 | - v.insert(r->str); | 156 | + v.emplace(r->str, r->len); |
| 157 | } | 157 | } |
| 158 | invoke(v); | 158 | invoke(v); |
| 159 | } | 159 | } |
| @@ -177,7 +177,7 @@ void Command<std::set<std::string>>::invoke_callback() { | @@ -177,7 +177,7 @@ void Command<std::set<std::string>>::invoke_callback() { | ||
| 177 | std::cerr << "[ERROR] " << cmd << ": Received non-array reply." << std::endl; | 177 | std::cerr << "[ERROR] " << cmd << ": Received non-array reply." << std::endl; |
| 178 | invoke_error(REDOX_WRONG_TYPE); | 178 | invoke_error(REDOX_WRONG_TYPE); |
| 179 | } | 179 | } |
| 180 | - v.insert(r->str); | 180 | + v.emplace(r->str, r->len); |
| 181 | } | 181 | } |
| 182 | invoke(v); | 182 | invoke(v); |
| 183 | } | 183 | } |
src/redox.cpp
| @@ -235,6 +235,30 @@ void Redox::command_callback(redisAsyncContext *ctx, void *r, void *privdata) { | @@ -235,6 +235,30 @@ void Redox::command_callback(redisAsyncContext *ctx, void *r, void *privdata) { | ||
| 235 | template<class ReplyT> | 235 | template<class ReplyT> |
| 236 | bool Redox::submit_to_server(Command<ReplyT>* c) { | 236 | bool Redox::submit_to_server(Command<ReplyT>* c) { |
| 237 | c->pending++; | 237 | c->pending++; |
| 238 | + | ||
| 239 | + // Process binary data if trailing quotation. This is a limited implementation | ||
| 240 | + // to allow binary data between the first and the last quotes of the command string, | ||
| 241 | + // if the very last character of the command is a quote ('"'). | ||
| 242 | + if(c->cmd[c->cmd.size()-1] == '"') { | ||
| 243 | + | ||
| 244 | + // Indices of the quotes | ||
| 245 | + int first = c->cmd.find('"'); | ||
| 246 | + int last = c->cmd.size()-1; | ||
| 247 | + | ||
| 248 | + // Proceed only if the first and last quotes are different | ||
| 249 | + if(first != last) { | ||
| 250 | + | ||
| 251 | + string format = c->cmd.substr(0, first) + "%b"; | ||
| 252 | + string value = c->cmd.substr(first+1, last-first-1); | ||
| 253 | + if (redisAsyncCommand(c->rdx->ctx, command_callback<ReplyT>, (void*)c->id, format.c_str(), value.c_str(), value.size()) != REDIS_OK) { | ||
| 254 | + cerr << "[ERROR] Could not send \"" << c->cmd << "\": " << c->rdx->ctx->errstr << endl; | ||
| 255 | + c->invoke_error(REDOX_SEND_ERROR); | ||
| 256 | + return false; | ||
| 257 | + } | ||
| 258 | + return true; | ||
| 259 | + } | ||
| 260 | + } | ||
| 261 | + | ||
| 238 | if (redisAsyncCommand(c->rdx->ctx, command_callback<ReplyT>, (void*)c->id, c->cmd.c_str()) != REDIS_OK) { | 262 | if (redisAsyncCommand(c->rdx->ctx, command_callback<ReplyT>, (void*)c->id, c->cmd.c_str()) != REDIS_OK) { |
| 239 | cerr << "[ERROR] Could not send \"" << c->cmd << "\": " << c->rdx->ctx->errstr << endl; | 263 | cerr << "[ERROR] Could not send \"" << c->cmd << "\": " << c->rdx->ctx->errstr << endl; |
| 240 | c->invoke_error(REDOX_SEND_ERROR); | 264 | c->invoke_error(REDOX_SEND_ERROR); |