Arduino-Redis
A Redis library for Arduino.
RedisInternal.cpp
1 #include <limits.h>
2 #include "RedisInternal.h"
3 
4 void RedisObject::init(Client& client)
5 {
6  data = client.readStringUntil('\r');
7  client.read(); // discard '\n'
8 }
9 
11 {
12  String emitStr((char)_type);
13  // Simple strings cannot contain CRLF, as they must terminate with CRLF
14  // https://redis.io/topics/protocol#resp-simple-strings
15  data.replace(CRLF, F(""));
16  emitStr += data;
17  emitStr += CRLF;
18  return emitStr;
19 }
20 
21 void RedisBulkString::init(Client& client)
22 {
23  RedisObject::init(client);
24 
25  auto dLen = String(data).toInt();
26  auto charBuf = new char[dLen + 1];
27  bzero(charBuf, dLen + 1);
28 
29  auto crlfCstr = String(CRLF).c_str();
30  if (client.readBytes(charBuf, dLen) != dLen || client.find(crlfCstr, 2)) {
31  Serial.printf("ERROR! Bad read\n");
32  exit(-1);
33  }
34 
35  data = String(charBuf);
36  delete [] charBuf;
37 }
38 
40 {
41  String emitStr((char)_type);
42  emitStr += String(data.length());
43  emitStr += CRLF;
44  emitStr += data;
45  emitStr += CRLF;
46  return emitStr;
47 }
48 
50 {
51  String emitStr((char)_type);
52  emitStr += String(vec.size());
53  emitStr += CRLF;
54  for (auto rTypeInst : vec) {
55  emitStr += rTypeInst->RESP();
56  }
57  return emitStr;
58 }
59 
60 std::shared_ptr<RedisObject> RedisCommand::issue(Client& cmdClient)
61 {
62  if (!cmdClient.connected())
63  return std::shared_ptr<RedisObject>(new RedisInternalError("Client is not connected"));
64 
65  auto cmdRespStr = RESP();
66 #if ARDUINO_REDIS_SERIAL_TRACE
67  Serial.printf("----- CMD ----\n%s---- /CMD ----\n", cmdRespStr.c_str());
68 #endif
69  cmdClient.print(cmdRespStr);
70  auto ret = RedisObject::parseType(cmdClient);
71  if (ret && ret->type() == RedisObject::Type::InternalError)
72  _err = (String)*ret;
73  return ret;
74 }
75 
76 template <>
77 int RedisCommand::issue_typed<int>(Client& cmdClient)
78 {
79  auto cmdRet = issue(cmdClient);
80  if (!cmdRet)
81  return INT_MAX - 0x0f;
82  if (cmdRet->type() != RedisObject::Type::Integer)
83  return INT_MAX - 0xf0;
84  return (int)*((RedisInteger*)cmdRet.get());
85 }
86 
87 template <>
88 bool RedisCommand::issue_typed<bool>(Client& cmdClient)
89 {
90  auto cmdRet = issue(cmdClient);
91  if (cmdRet && cmdRet->type() == RedisObject::Type::Integer)
92  return (bool)*((RedisInteger*)cmdRet.get());
93  return false;
94 }
95 
96 template <>
97 String RedisCommand::issue_typed<String>(Client& cmdClient)
98 {
99  return (String)*issue(cmdClient);
100 }
101 
102 typedef std::map<RedisObject::Type, std::function<RedisObject*(Client&)>> TypeParseMap;
103 
104 static TypeParseMap g_TypeParseMap {
105  { RedisObject::Type::SimpleString, [](Client& c) { return new RedisSimpleString(c); } },
106  { RedisObject::Type::BulkString, [](Client& c) { return new RedisBulkString(c); } },
107  { RedisObject::Type::Integer, [](Client& c) { return new RedisInteger(c); } },
108  { RedisObject::Type::Array, [](Client& c) { return new RedisArray(c); } },
109  { RedisObject::Type::Error, [](Client& c) { return new RedisError(c); } }
110 };
111 
112 std::shared_ptr<RedisObject> RedisObject::parseType(Client& client)
113 {
114  if (client.connected()) {
115  while (!client.available()) {
116  delay(1);
117  }
118 
119  auto typeChar = (RedisObject::Type)client.read();
120 
121 #if ARDUINO_REDIS_SERIAL_TRACE
122  Serial.printf("Parsed type character '%c' (0x%x)\n", typeChar, typeChar);
123 #endif
124 
125  if (g_TypeParseMap.find(typeChar) != g_TypeParseMap.end()) {
126  auto retVal = g_TypeParseMap[typeChar](client);
127 
128  if (!retVal || retVal->type() == RedisObject::Type::Error) {
129  String err = retVal ? (String)*retVal : "(nil)";
130  return std::shared_ptr<RedisObject>(new RedisInternalError(err));
131  }
132 
133  return std::shared_ptr<RedisObject>(retVal);
134  }
135 
136  return std::shared_ptr<RedisObject>(new RedisInternalError("Unable to find type: " + typeChar));
137  }
138 
139  return std::shared_ptr<RedisObject>(new RedisInternalError("Not connected"));
140 }
141 
virtual String RESP() override
std::shared_ptr< RedisObject > issue(Client &cmdClient)
virtual String RESP() override
virtual void init(Client &client) override
virtual String RESP() override
virtual String RESP()=0
virtual void init(Client &client)