Arduino-Redis
A Redis library for Arduino.
RedisInternal.cpp
Go to the documentation of this file.
1 #include "RedisInternal.h"
2 #include <map>
3 #include <limits.h>
4 #include <memory>
5 
6 void RedisObject::init(Client &client)
7 {
8  data = client.readStringUntil('\r');
9  client.read(); // discard '\n'
10 }
11 
13 {
14  String emitStr((char)_type);
15  // Simple strings cannot contain CRLF, as they must terminate with CRLF
16  // https://redis.io/topics/protocol#resp-simple-strings
17  data.replace(CRLF, F(""));
18  emitStr += data;
19  emitStr += CRLF;
20  return emitStr;
21 }
22 
23 void RedisBulkString::init(Client &client)
24 {
25  auto dLen = data.toInt();
26 
27  // "Null Bulk String" -- https://redis.io/topics/protocol#resp-bulk-strings
28  if (dLen == -1)
29  {
30  data = (const char *)nullptr;
31  return;
32  }
33 
34  auto charBuf = new char[dLen + 1];
35  bzero(charBuf, dLen + 1);
36 
37  auto readB = client.readBytes(charBuf, dLen);
38  if ((int)readB != dLen)
39  {
40  Serial.printf("ERROR! Bad read (%ld ?= %ld)\n", (long)readB, (long)dLen);
41  exit(-1);
42  }
43 
44  data = String(charBuf);
45  delete[] charBuf;
46 }
47 
49 {
50  String emitStr((char)_type);
51  emitStr += String(data.length());
52  emitStr += CRLF;
53  emitStr += data;
54  emitStr += CRLF;
55  return emitStr;
56 }
57 
58 void RedisArray::init(Client &client)
59 {
60  for (int i = 0; i < data.toInt(); i++)
61  add(RedisObject::parseType(client));
62 }
63 
64 RedisArray::operator std::vector<String>() const
65 {
66  std::vector<String> result;
67 
68  for(uint i = 0; i < vec.size(); i++)
69  {
70  std::shared_ptr<RedisObject> obj = vec.at(i);
71  String rowVal;
72  uint index = i + 1;
73 
74  if(obj->type() == RedisObject::Type::Array)
75  {
76  std::vector<String> nestedArray =
77  (std::vector<String>)*((RedisArray *)obj.get());
78 
79  for(uint j = 0; j < nestedArray.size(); j++)
80  {
81  if(j == 0)
82  {
83  result.push_back(String(index) + ") " + nestedArray.at(j));
84  }
85  else
86  {
87  result.push_back(" " + nestedArray.at(j));
88  }
89  }
90  }
91  else if(obj->type() == RedisObject::Type::BulkString ||
92  obj->type() == RedisObject::SimpleString ||
93  obj->type() == RedisObject::Integer)
94  {
95  rowVal = String(*obj);
96  result.push_back(String(index) + ") " + rowVal);
97  }
98  else
99  {
100  rowVal = "Unknown";
101  result.push_back(String(index) + ") " + rowVal);
102  }
103  }
104  return result;
105 }
106 
108 {
109  String emitStr((char)_type);
110  emitStr += String(vec.size());
111  emitStr += CRLF;
112  for (auto rTypeInst : vec)
113  {
114  emitStr += rTypeInst->RESP();
115  }
116  return emitStr;
117 }
118 
119 std::shared_ptr<RedisObject> RedisCommand::issue(Client &cmdClient)
120 {
121  if (!cmdClient.connected())
122  return std::shared_ptr<RedisObject>(new RedisInternalError(RedisInternalError::Disconnected));
123 
124  auto cmdRespStr = RESP();
125  cmdClient.print(cmdRespStr);
126  auto ret = RedisObject::parseType(cmdClient);
127  if (ret && ret->type() == RedisObject::Type::InternalError)
128  _err = (String)*ret;
129  return ret;
130 }
131 
132 template <>
133 int RedisCommand::issue_typed<int>(Client &cmdClient)
134 {
135  auto cmdRet = issue(cmdClient);
136  if (!cmdRet)
137  return INT_MAX - 0x0f;
138  if (cmdRet->type() != RedisObject::Type::Integer)
139  return INT_MAX - 0xf0;
140  return (int)*((RedisInteger *)cmdRet.get());
141 }
142 
143 template <>
144 bool RedisCommand::issue_typed<bool>(Client &cmdClient)
145 {
146  auto cmdRet = issue(cmdClient);
147  if (cmdRet && cmdRet->type() == RedisObject::Type::Integer)
148  return (bool)*((RedisInteger *)cmdRet.get());
149  return false;
150 }
151 
152 template <>
153 String RedisCommand::issue_typed<String>(Client &cmdClient)
154 {
155  return (String)*issue(cmdClient);
156 }
157 
158 typedef std::map<RedisObject::Type, std::function<RedisObject *(Client &)>> TypeParseMap;
159 
160 static TypeParseMap g_TypeParseMap{
161  {RedisObject::Type::SimpleString, [](Client &c)
162  { return new RedisSimpleString(c); }},
163  {RedisObject::Type::BulkString, [](Client &c)
164  { return new RedisBulkString(c); }},
165  {RedisObject::Type::Integer, [](Client &c)
166  { return new RedisInteger(c); }},
167  {RedisObject::Type::Array, [](Client &c)
168  { return new RedisArray(c); }},
169  {RedisObject::Type::Error, [](Client &c)
170  { return new RedisError(c); }}};
171 
172 std::shared_ptr<RedisObject> RedisObject::parseTypeNonBlocking(Client &client)
173 {
174  if (client.connected() && !client.available()) {
175  return nullptr;
176  }
177 
178  RedisObject::Type typeChar = RedisObject::Type::NoType;
179  if (!client.connected())
180  {
181  return std::shared_ptr<RedisObject>(new RedisInternalError(RedisInternalError::Disconnected));
182  }
183 
184  typeChar = (RedisObject::Type)client.read();
185  if (typeChar == -1 || typeChar == '\r' || typeChar == '\n') {
186  return nullptr;
187  };
188 
189  if (g_TypeParseMap.find(typeChar) != g_TypeParseMap.end())
190  {
191  auto retVal = g_TypeParseMap[typeChar](client);
192 
193  if (!retVal || retVal->type() == RedisObject::Type::Error)
194  {
195  String err = retVal ? (String)*retVal : "(nil)";
196  return std::shared_ptr<RedisObject>(new RedisInternalError(RedisInternalError::UnknownError, err));
197  }
198 
199  return std::shared_ptr<RedisObject>(retVal);
200  }
201 
202  return std::shared_ptr<RedisObject>(new RedisInternalError(RedisInternalError::UnknownType, String(typeChar)));
203 }
204 
205 std::shared_ptr<RedisObject> RedisObject::parseType(Client &client)
206 {
207  std::shared_ptr<RedisObject> type = nullptr;
208  while (type==nullptr) {
209  type = parseTypeNonBlocking(client);
210  }
211  return type;
212 }
RedisObject::init
virtual void init(Client &client)
Definition: RedisInternal.cpp:6
RedisCommand::issue
std::shared_ptr< RedisObject > issue(Client &cmdClient)
Definition: RedisInternal.cpp:119
RedisBulkString::init
virtual void init(Client &client) override
Definition: RedisInternal.cpp:23
RedisError
Definition: RedisInternal.h:122
RedisArray::add
void add(std::shared_ptr< RedisObject > param)
Definition: RedisInternal.h:98
RedisSimpleString::RESP
virtual String RESP() override
Definition: RedisInternal.cpp:12
RedisArray::vec
std::vector< std::shared_ptr< RedisObject > > vec
Definition: RedisInternal.h:107
RedisArray::RESP
virtual String RESP() override
Definition: RedisInternal.cpp:107
RedisObject::_type
Type _type
Definition: RedisInternal.h:64
RedisSimpleString
Definition: RedisInternal.h:68
RedisObject
Definition: RedisInternal.h:22
RedisObject::SimpleString
@ SimpleString
Definition: RedisInternal.h:29
RedisObject::Type
Type
Definition: RedisInternal.h:26
RedisObject::parseTypeNonBlocking
static std::shared_ptr< RedisObject > parseTypeNonBlocking(Client &)
Definition: RedisInternal.cpp:172
RedisInternalError::Disconnected
@ Disconnected
Definition: RedisInternal.h:137
RedisInteger
Definition: RedisInternal.h:111
RedisArray::init
virtual void init(Client &client) override
Definition: RedisInternal.cpp:58
RedisBulkString
Definition: RedisInternal.h:78
RedisObject::type
Type type() const
Definition: RedisInternal.h:60
RedisObject::Integer
@ Integer
Definition: RedisInternal.h:31
RedisArray
Definition: RedisInternal.h:91
RedisInternal.h
CRLF
#define CRLF
Definition: RedisInternal.h:10
RedisInternalError
Definition: RedisInternal.h:130
RedisObject::parseType
static std::shared_ptr< RedisObject > parseType(Client &)
Definition: RedisInternal.cpp:205
TypeParseMap
std::map< RedisObject::Type, std::function< RedisObject *(Client &)> > TypeParseMap
Definition: RedisInternal.cpp:158
RedisInternalError::UnknownError
@ UnknownError
Definition: RedisInternal.h:135
RedisBulkString::RESP
virtual String RESP() override
Definition: RedisInternal.cpp:48
RedisObject::data
String data
Definition: RedisInternal.h:63
RedisInternalError::UnknownType
@ UnknownType
Definition: RedisInternal.h:136