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