Commit c6dbba89b067ac3e6fcf691f3c8a856ac3ef1b5c

Authored by Hayk Martirosyan
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.
CMakeLists.txt
... ... @@ -84,4 +84,7 @@ if (examples)
84 84 add_executable(multi_client examples/multi-client.cpp ${SRC_ALL})
85 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 90 endif()
... ...
README.md
1 1 redox
2 2 ======
3 3  
4   -Modern, asynchronous, and wicked fast C++11 bindings for Redis
  4 +Modern, asynchronous, and wicked fast C++11 client for Redis
5 5  
6 6 ## Overview
7 7  
... ...
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&lt;std::string&gt;::invoke_callback() {
46 46 invoke_error(REDOX_WRONG_TYPE);
47 47  
48 48 } else {
49   - std::string s = reply_obj->str;
  49 + std::string s(reply_obj->str, reply_obj->len);
50 50 invoke(s);
51 51 }
52 52 }
... ... @@ -129,7 +129,7 @@ void Command&lt;std::vector&lt;std::string&gt;&gt;::invoke_callback() {
129 129 std::cerr << "[ERROR] " << cmd << ": Received non-array reply." << std::endl;
130 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 134 invoke(v);
135 135 }
... ... @@ -153,7 +153,7 @@ void Command&lt;std::unordered_set&lt;std::string&gt;&gt;::invoke_callback() {
153 153 std::cerr << "[ERROR] " << cmd << ": Received non-array reply." << std::endl;
154 154 invoke_error(REDOX_WRONG_TYPE);
155 155 }
156   - v.insert(r->str);
  156 + v.emplace(r->str, r->len);
157 157 }
158 158 invoke(v);
159 159 }
... ... @@ -177,7 +177,7 @@ void Command&lt;std::set&lt;std::string&gt;&gt;::invoke_callback() {
177 177 std::cerr << "[ERROR] " << cmd << ": Received non-array reply." << std::endl;
178 178 invoke_error(REDOX_WRONG_TYPE);
179 179 }
180   - v.insert(r->str);
  180 + v.emplace(r->str, r->len);
181 181 }
182 182 invoke(v);
183 183 }
... ...
src/redox.cpp
... ... @@ -235,6 +235,30 @@ void Redox::command_callback(redisAsyncContext *ctx, void *r, void *privdata) {
235 235 template<class ReplyT>
236 236 bool Redox::submit_to_server(Command<ReplyT>* c) {
237 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 262 if (redisAsyncCommand(c->rdx->ctx, command_callback<ReplyT>, (void*)c->id, c->cmd.c_str()) != REDIS_OK) {
239 263 cerr << "[ERROR] Could not send \"" << c->cmd << "\": " << c->rdx->ctx->errstr << endl;
240 264 c->invoke_error(REDOX_SEND_ERROR);
... ...