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 
5 void RedisObject::init(Client &client)
6 {
7  data = client.readStringUntil('\r');
8  client.read(); // discard '\n'
9 }
10 
12 {
13  String emitStr((char)_type);
14  // Simple strings cannot contain CRLF, as they must terminate with CRLF
15  // https://redis.io/topics/protocol#resp-simple-strings
16  data.replace(CRLF, F(""));
17  emitStr += data;
18  emitStr += CRLF;
19  return emitStr;
20 }
21 
22 void RedisBulkString::init(Client &client)
23 {
24  auto dLen = data.toInt();
25 
26  // "Null Bulk String" -- https://redis.io/topics/protocol#resp-bulk-strings
27  if (dLen == -1)
28  {
29  data = (const char *)nullptr;
30  return;
31  }
32 
33  auto charBuf = new char[dLen + 1];
34  bzero(charBuf, dLen + 1);
35 
36  auto readB = client.readBytes(charBuf, dLen);
37  if (readB != dLen)
38  {
39  Serial.printf("ERROR! Bad read (%ld ?= %ld)\n", (long)readB, (long)dLen);
40  exit(-1);
41  }
42 
43  data = String(charBuf);
44  delete[] charBuf;
45 }
46 
48 {
49  String emitStr((char)_type);
50  emitStr += String(data.length());
51  emitStr += CRLF;
52  emitStr += data;
53  emitStr += CRLF;
54  return emitStr;
55 }
56 
57 void RedisArray::init(Client &client)
58 {
59  for (int i = 0; i < data.toInt(); i++)
60  add(RedisObject::parseType(client));
61 }
62 
63 RedisArray::operator std::vector<String>() const
64 {
65  std::vector<String> rv;
66  for (auto ro : vec)
67  rv.push_back((String)*ro.get());
68  return rv;
69 }
70 
72 {
73  String emitStr((char)_type);
74  emitStr += String(vec.size());
75  emitStr += CRLF;
76  for (auto rTypeInst : vec)
77  {
78  emitStr += rTypeInst->RESP();
79  }
80  return emitStr;
81 }
82 
83 std::shared_ptr<RedisObject> RedisCommand::issue(Client &cmdClient)
84 {
85  if (!cmdClient.connected())
86  return std::shared_ptr<RedisObject>(new RedisInternalError(RedisInternalError::Disconnected));
87 
88  auto cmdRespStr = RESP();
89  cmdClient.print(cmdRespStr);
90  auto ret = RedisObject::parseType(cmdClient);
91  if (ret && ret->type() == RedisObject::Type::InternalError)
92  _err = (String)*ret;
93  return ret;
94 }
95 
96 template <>
97 int RedisCommand::issue_typed<int>(Client &cmdClient)
98 {
99  auto cmdRet = issue(cmdClient);
100  if (!cmdRet)
101  return INT_MAX - 0x0f;
102  if (cmdRet->type() != RedisObject::Type::Integer)
103  return INT_MAX - 0xf0;
104  return (int)*((RedisInteger *)cmdRet.get());
105 }
106 
107 template <>
108 bool RedisCommand::issue_typed<bool>(Client &cmdClient)
109 {
110  auto cmdRet = issue(cmdClient);
111  if (cmdRet && cmdRet->type() == RedisObject::Type::Integer)
112  return (bool)*((RedisInteger *)cmdRet.get());
113  return false;
114 }
115 
116 template <>
117 String RedisCommand::issue_typed<String>(Client &cmdClient)
118 {
119  return (String)*issue(cmdClient);
120 }
121 
122 typedef std::map<RedisObject::Type, std::function<RedisObject *(Client &)>> TypeParseMap;
123 
124 static TypeParseMap g_TypeParseMap{
125  {RedisObject::Type::SimpleString, [](Client &c) { return new RedisSimpleString(c); }},
126  {RedisObject::Type::BulkString, [](Client &c) { return new RedisBulkString(c); }},
127  {RedisObject::Type::Integer, [](Client &c) { return new RedisInteger(c); }},
128  {RedisObject::Type::Array, [](Client &c) { return new RedisArray(c); }},
129  {RedisObject::Type::Error, [](Client &c) { return new RedisError(c); }}};
130 
131 std::shared_ptr<RedisObject> RedisObject::parseType(Client &client)
132 {
133  while (client.connected() && !client.available())
134  ;
135 
136  RedisObject::Type typeChar = RedisObject::Type::NoType;
137  do
138  {
139  if (!client.connected())
140  {
141  return std::shared_ptr<RedisObject>(new RedisInternalError(RedisInternalError::Disconnected));
142  }
143 
144  typeChar = (RedisObject::Type)client.read();
145  } while (typeChar == -1 || typeChar == '\r' || typeChar == '\n');
146 
147  if (g_TypeParseMap.find(typeChar) != g_TypeParseMap.end())
148  {
149  auto retVal = g_TypeParseMap[typeChar](client);
150 
151  if (!retVal || retVal->type() == RedisObject::Type::Error)
152  {
153  String err = retVal ? (String)*retVal : "(nil)";
154  return std::shared_ptr<RedisObject>(new RedisInternalError(RedisInternalError::UnknownError, err));
155  }
156 
157  return std::shared_ptr<RedisObject>(retVal);
158  }
159 
160  return std::shared_ptr<RedisObject>(new RedisInternalError(RedisInternalError::UnknownType, String(typeChar)));
161 }
RedisObject::init
virtual void init(Client &client)
Definition: RedisInternal.cpp:5
RedisCommand::issue
std::shared_ptr< RedisObject > issue(Client &cmdClient)
Definition: RedisInternal.cpp:83
RedisBulkString::init
virtual void init(Client &client) override
Definition: RedisInternal.cpp:22
RedisError
Definition: RedisInternal.h:121
RedisArray::add
void add(std::shared_ptr< RedisObject > param)
Definition: RedisInternal.h:97
RedisSimpleString::RESP
virtual String RESP() override
Definition: RedisInternal.cpp:11
RedisArray::vec
std::vector< std::shared_ptr< RedisObject > > vec
Definition: RedisInternal.h:106
RedisArray::RESP
virtual String RESP() override
Definition: RedisInternal.cpp:71
RedisObject::_type
Type _type
Definition: RedisInternal.h:63
RedisSimpleString
Definition: RedisInternal.h:67
RedisObject
Definition: RedisInternal.h:22
RedisObject::Type
Type
Definition: RedisInternal.h:26
RedisInternalError::Disconnected
@ Disconnected
Definition: RedisInternal.h:136
RedisInteger
Definition: RedisInternal.h:110
RedisArray::init
virtual void init(Client &client) override
Definition: RedisInternal.cpp:57
RedisBulkString
Definition: RedisInternal.h:77
RedisArray
Definition: RedisInternal.h:90
RedisInternal.h
CRLF
#define CRLF
Definition: RedisInternal.h:10
RedisInternalError
Definition: RedisInternal.h:129
RedisObject::parseType
static std::shared_ptr< RedisObject > parseType(Client &)
Definition: RedisInternal.cpp:131
TypeParseMap
std::map< RedisObject::Type, std::function< RedisObject *(Client &)> > TypeParseMap
Definition: RedisInternal.cpp:122
RedisInternalError::UnknownError
@ UnknownError
Definition: RedisInternal.h:134
RedisBulkString::RESP
virtual String RESP() override
Definition: RedisInternal.cpp:47
RedisObject::data
String data
Definition: RedisInternal.h:62
RedisInternalError::UnknownType
@ UnknownType
Definition: RedisInternal.h:135