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  cmdClient.print(cmdRespStr);
87  auto ret = RedisObject::parseType(cmdClient);
88  if (ret && ret->type() == RedisObject::Type::InternalError)
89  _err = (String)*ret;
90  return ret;
91 }
92 
93 template <>
94 int RedisCommand::issue_typed<int>(Client& cmdClient)
95 {
96  auto cmdRet = issue(cmdClient);
97  if (!cmdRet)
98  return INT_MAX - 0x0f;
99  if (cmdRet->type() != RedisObject::Type::Integer)
100  return INT_MAX - 0xf0;
101  return (int)*((RedisInteger*)cmdRet.get());
102 }
103 
104 template <>
105 bool RedisCommand::issue_typed<bool>(Client& cmdClient)
106 {
107  auto cmdRet = issue(cmdClient);
108  if (cmdRet && cmdRet->type() == RedisObject::Type::Integer)
109  return (bool)*((RedisInteger*)cmdRet.get());
110  return false;
111 }
112 
113 template <>
114 String RedisCommand::issue_typed<String>(Client& cmdClient)
115 {
116  return (String)*issue(cmdClient);
117 }
118 
119 typedef std::map<RedisObject::Type, std::function<RedisObject*(Client&)>> TypeParseMap;
120 
121 static TypeParseMap g_TypeParseMap {
122  { RedisObject::Type::SimpleString, [](Client& c) { return new RedisSimpleString(c); } },
123  { RedisObject::Type::BulkString, [](Client& c) { return new RedisBulkString(c); } },
124  { RedisObject::Type::Integer, [](Client& c) { return new RedisInteger(c); } },
125  { RedisObject::Type::Array, [](Client& c) { return new RedisArray(c); } },
126  { RedisObject::Type::Error, [](Client& c) { return new RedisError(c); } }
127 };
128 
129 std::shared_ptr<RedisObject> RedisObject::parseType(Client& client)
130 {
131  if (client.connected()) {
132  while (!client.available());
133 
134  RedisObject::Type typeChar = RedisObject::Type::NoType;
135  do {
136  typeChar = (RedisObject::Type)client.read();
137  } while (typeChar == -1 || typeChar == '\r' || typeChar == '\n');
138 
139  if (g_TypeParseMap.find(typeChar) != g_TypeParseMap.end()) {
140  auto retVal = g_TypeParseMap[typeChar](client);
141 
142  if (!retVal || retVal->type() == RedisObject::Type::Error) {
143  String err = retVal ? (String)*retVal : "(nil)";
144  return std::shared_ptr<RedisObject>(new RedisInternalError(err));
145  }
146 
147  return std::shared_ptr<RedisObject>(retVal);
148  }
149 
150  return std::shared_ptr<RedisObject>(new RedisInternalError("Unable to find type: " + typeChar));
151  }
152 
153  return std::shared_ptr<RedisObject>(new RedisInternalError("Not connected"));
154 }
155 
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:115
RedisSimpleString::RESP
virtual String RESP() override
Definition: RedisInternal.cpp:11
RedisArray::RESP
virtual String RESP() override
Definition: RedisInternal.cpp:69
RedisSimpleString
Definition: RedisInternal.h:65
RedisObject
Definition: RedisInternal.h:22
RedisObject::Type
Type
Definition: RedisInternal.h:25
RedisInteger
Definition: RedisInternal.h:105
RedisArray::init
virtual void init(Client &client) override
Definition: RedisInternal.cpp:55
RedisBulkString
Definition: RedisInternal.h:74
RedisArray
Definition: RedisInternal.h:86
RedisInternalError
Definition: RedisInternal.h:123
RedisBulkString::RESP
virtual String RESP() override
Definition: RedisInternal.cpp:45