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 
72  if(obj->type() == RedisObject::Type::Array)
73  {
74  std::vector<String> nestedArray =
75  (std::vector<String>)*((RedisArray *)obj.get());
76 
77  for(uint j = 0; j < nestedArray.size(); j++)
78  {
79  result.push_back(nestedArray.at(j));
80  }
81  }
82  else if(obj->type() == RedisObject::Type::BulkString ||
83  obj->type() == RedisObject::SimpleString ||
84  obj->type() == RedisObject::Integer)
85  {
86  result.push_back(String(*obj));
87  }
88  else
89  {
90  result.push_back("Unknown");
91  }
92  }
93  return result;
94 }
95 
97 {
98  String emitStr((char)_type);
99  emitStr += String(vec.size());
100  emitStr += CRLF;
101  for (auto rTypeInst : vec)
102  {
103  emitStr += rTypeInst->RESP();
104  }
105  return emitStr;
106 }
107 
108 std::shared_ptr<RedisObject> RedisCommand::issue(Client &cmdClient)
109 {
110  if (!cmdClient.connected())
111  return std::shared_ptr<RedisObject>(new RedisInternalError(RedisInternalError::Disconnected));
112 
113  auto cmdRespStr = RESP();
114  cmdClient.print(cmdRespStr);
115  auto ret = RedisObject::parseType(cmdClient);
116  if (ret && ret->type() == RedisObject::Type::InternalError)
117  _err = (String)*ret;
118  return ret;
119 }
120 
121 template <>
122 int RedisCommand::issue_typed<int>(Client &cmdClient)
123 {
124  auto cmdRet = issue(cmdClient);
125  if (!cmdRet)
126  return INT_MAX - 0x0f;
127  if (cmdRet->type() != RedisObject::Type::Integer)
128  return INT_MAX - 0xf0;
129  return (int)*((RedisInteger *)cmdRet.get());
130 }
131 
132 template <>
133 bool RedisCommand::issue_typed<bool>(Client &cmdClient)
134 {
135  auto cmdRet = issue(cmdClient);
136  if (cmdRet && cmdRet->type() == RedisObject::Type::Integer)
137  return (bool)*((RedisInteger *)cmdRet.get());
138  return false;
139 }
140 
141 template <>
142 String RedisCommand::issue_typed<String>(Client &cmdClient)
143 {
144  return (String)*issue(cmdClient);
145 }
146 
147 typedef std::map<RedisObject::Type, std::function<RedisObject *(Client &)>> TypeParseMap;
148 
149 static TypeParseMap g_TypeParseMap{
150  {RedisObject::Type::SimpleString, [](Client &c)
151  { return new RedisSimpleString(c); }},
152  {RedisObject::Type::BulkString, [](Client &c)
153  { return new RedisBulkString(c); }},
154  {RedisObject::Type::Integer, [](Client &c)
155  { return new RedisInteger(c); }},
156  {RedisObject::Type::Array, [](Client &c)
157  { return new RedisArray(c); }},
158  {RedisObject::Type::Error, [](Client &c)
159  { return new RedisError(c); }}};
160 
161 std::shared_ptr<RedisObject> RedisObject::parseTypeNonBlocking(Client &client)
162 {
163  if (client.connected() && !client.available()) {
164  return nullptr;
165  }
166 
167  RedisObject::Type typeChar = RedisObject::Type::NoType;
168  if (!client.connected())
169  {
170  return std::shared_ptr<RedisObject>(new RedisInternalError(RedisInternalError::Disconnected));
171  }
172 
173  typeChar = (RedisObject::Type)client.read();
174  if (typeChar == -1 || typeChar == '\r' || typeChar == '\n') {
175  return nullptr;
176  };
177 
178  if (g_TypeParseMap.find(typeChar) != g_TypeParseMap.end())
179  {
180  auto retVal = g_TypeParseMap[typeChar](client);
181 
182  if (!retVal || retVal->type() == RedisObject::Type::Error)
183  {
184  String err = retVal ? (String)*retVal : "(nil)";
185  return std::shared_ptr<RedisObject>(new RedisInternalError(RedisInternalError::UnknownError, err));
186  }
187 
188  return std::shared_ptr<RedisObject>(retVal);
189  }
190 
191  return std::shared_ptr<RedisObject>(new RedisInternalError(RedisInternalError::UnknownType, String(typeChar)));
192 }
193 
194 std::shared_ptr<RedisObject> RedisObject::parseType(Client &client)
195 {
196  std::shared_ptr<RedisObject> type = nullptr;
197  while (type==nullptr) {
198  type = parseTypeNonBlocking(client);
199  }
200  return type;
201 }
RedisObject::init
virtual void init(Client &client)
Definition: RedisInternal.cpp:6
RedisCommand::issue
std::shared_ptr< RedisObject > issue(Client &cmdClient)
Definition: RedisInternal.cpp:108
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:96
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:161
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:194
TypeParseMap
std::map< RedisObject::Type, std::function< RedisObject *(Client &)> > TypeParseMap
Definition: RedisInternal.cpp:147
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