Arduino-Redis
A Redis library for Arduino.
RedisInternal.cpp
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  data = (const char*)nullptr;
29  return;
30  }
31 
32  auto charBuf = new char[dLen + 1];
33  bzero(charBuf, dLen + 1);
34 
35  auto readB = client.readBytes(charBuf, dLen);
36  if (readB != dLen) {
37  Serial.printf("ERROR! Bad read (%ld ?= %ld)\n", (long)readB, (long)dLen);
38  exit(-1);
39  }
40 
41  data = String(charBuf);
42  delete [] charBuf;
43 }
44 
46 {
47  String emitStr((char)_type);
48  emitStr += String(data.length());
49  emitStr += CRLF;
50  emitStr += data;
51  emitStr += CRLF;
52  return emitStr;
53 }
54 
55 void RedisArray::init(Client& client)
56 {
57  for (int i = 0; i < data.toInt(); i++)
58  add(RedisObject::parseType(client));
59 }
60 
61 RedisArray::operator std::vector<String>() const
62 {
63  std::vector<String> rv;
64  for (auto ro : vec)
65  rv.push_back((String)*ro.get());
66  return rv;
67 }
68 
70 {
71  String emitStr((char)_type);
72  emitStr += String(vec.size());
73  emitStr += CRLF;
74  for (auto rTypeInst : vec) {
75  emitStr += rTypeInst->RESP();
76  }
77  return emitStr;
78 }
79 
80 std::shared_ptr<RedisObject> RedisCommand::issue(Client& cmdClient)
81 {
82  if (!cmdClient.connected())
83  return std::shared_ptr<RedisObject>(new RedisInternalError("Client is not connected"));
84 
85  auto cmdRespStr = RESP();
86  sprint("----- CMD ----\n%s---- /CMD ----\n", cmdRespStr.c_str());
87  cmdClient.print(cmdRespStr);
88  auto ret = RedisObject::parseType(cmdClient);
89  if (ret && ret->type() == RedisObject::Type::InternalError)
90  _err = (String)*ret;
91  return ret;
92 }
93 
94 template <>
95 int RedisCommand::issue_typed<int>(Client& cmdClient)
96 {
97  auto cmdRet = issue(cmdClient);
98  if (!cmdRet)
99  return INT_MAX - 0x0f;
100  if (cmdRet->type() != RedisObject::Type::Integer)
101  return INT_MAX - 0xf0;
102  return (int)*((RedisInteger*)cmdRet.get());
103 }
104 
105 template <>
106 bool RedisCommand::issue_typed<bool>(Client& cmdClient)
107 {
108  auto cmdRet = issue(cmdClient);
109  if (cmdRet && cmdRet->type() == RedisObject::Type::Integer)
110  return (bool)*((RedisInteger*)cmdRet.get());
111  return false;
112 }
113 
114 template <>
115 String RedisCommand::issue_typed<String>(Client& cmdClient)
116 {
117  return (String)*issue(cmdClient);
118 }
119 
120 typedef std::map<RedisObject::Type, std::function<RedisObject*(Client&)>> TypeParseMap;
121 
122 static TypeParseMap g_TypeParseMap {
123  { RedisObject::Type::SimpleString, [](Client& c) { return new RedisSimpleString(c); } },
124  { RedisObject::Type::BulkString, [](Client& c) { return new RedisBulkString(c); } },
125  { RedisObject::Type::Integer, [](Client& c) { return new RedisInteger(c); } },
126  { RedisObject::Type::Array, [](Client& c) { return new RedisArray(c); } },
127  { RedisObject::Type::Error, [](Client& c) { return new RedisError(c); } }
128 };
129 
130 std::shared_ptr<RedisObject> RedisObject::parseType(Client& client)
131 {
132  if (client.connected()) {
133  while (!client.available());
134 
135 #if ARDUINO_REDIS_SERIAL_TRACE
136  int readB = 0;
137 #endif
138  RedisObject::Type typeChar = RedisObject::Type::NoType;
139  do {
140  typeChar = (RedisObject::Type)client.read();
141 #if ARDUINO_REDIS_SERIAL_TRACE
142  ++readB;
143 #endif
144  } while (typeChar == -1 || typeChar == '\r' || typeChar == '\n');
145 
146 #if ARDUINO_REDIS_SERIAL_TRACE
147  sprint("Parsed type character '%c' (after %d reads) (0x%x, %dd)\n", typeChar, readB, typeChar, (int)typeChar);
148 #endif
149 
150  if (g_TypeParseMap.find(typeChar) != g_TypeParseMap.end()) {
151  auto retVal = g_TypeParseMap[typeChar](client);
152 
153  if (!retVal || retVal->type() == RedisObject::Type::Error) {
154  String err = retVal ? (String)*retVal : "(nil)";
155  return std::shared_ptr<RedisObject>(new RedisInternalError(err));
156  }
157 
158  return std::shared_ptr<RedisObject>(retVal);
159  }
160 
161  return std::shared_ptr<RedisObject>(new RedisInternalError("Unable to find type: " + typeChar));
162  }
163 
164  return std::shared_ptr<RedisObject>(new RedisInternalError("Not connected"));
165 }
166 
RedisObject::init
virtual void init(Client &client)
Definition: RedisInternal.cpp:5
RedisCommand::issue
std::shared_ptr< RedisObject > issue(Client &cmdClient)
Definition: RedisInternal.cpp:80
RedisBulkString::init
virtual void init(Client &client) override
Definition: RedisInternal.cpp:22
RedisError
Definition: RedisInternal.h:118
RedisSimpleString::RESP
virtual String RESP() override
Definition: RedisInternal.cpp:11
RedisArray::RESP
virtual String RESP() override
Definition: RedisInternal.cpp:69
RedisSimpleString
Definition: RedisInternal.h:68
RedisObject
Definition: RedisInternal.h:25
RedisObject::Type
Type
Definition: RedisInternal.h:28
RedisInteger
Definition: RedisInternal.h:108
RedisArray::init
virtual void init(Client &client) override
Definition: RedisInternal.cpp:55
RedisBulkString
Definition: RedisInternal.h:77
RedisArray
Definition: RedisInternal.h:89
RedisInternalError
Definition: RedisInternal.h:126
RedisBulkString::RESP
virtual String RESP() override
Definition: RedisInternal.cpp:45