Skip to content

Commit 100251f

Browse files
committed
[feature] #2
1 parent dd23141 commit 100251f

File tree

3 files changed

+184
-71
lines changed

3 files changed

+184
-71
lines changed

README.md

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
IoT Protocol is a protocol over TCP based on HTTP for light data traffic.
44

5+
**Motivation**: HTTP 1.1 (*http://*) request minimum size is 26 bytes (https://stackoverflow.com/a/25065027/1956719) and the HOST param is mandatory for all requests.
6+
7+
The IOT_PROTOCOL (*iot://*) request minimum size is 8 bytes withless to require HOST param for requests.
8+
59
## Preamble Version 1
610

711
```js
@@ -16,8 +20,9 @@ PATH\n
1620

1721
Version is the version of iot protocol. Used for compatibility.
1822

19-
- Type: `byte` | `uint8_t`. **REQUIRED**
20-
- Example: `1`
23+
* Type: `byte` | `uint8_t`. **REQUIRED**
24+
* Size: 1 byte
25+
* Example: `1`
2126

2227
### METHOD_ID
2328

@@ -26,28 +31,29 @@ Method ID: METHOD+ID.
2631
Methods:
2732

2833
* Type: `char`. **REQUIRED**
34+
* Size: 1 byte
2935
* Example: `R`
3036

31-
- `R` | `0x82`: *Request* method used to do calls needs a response
3237
- `S` | `0x83`: *Signal* method used to send signals like events
38+
- `R` | `0x82`: *Request* method used to do calls needs a response
39+
- `r` | `0x114`: *Response* method used to responds a request
3340

3441

3542
ID:
3643

3744
Unsigned random number with up to 2^16 that identifies the request.
3845

3946
* Type: `uint16_t` as Big Endian format. **REQUIRED**
47+
* Size: 2 bytes
4048
* Example: `1822`
4149

4250
### PATH
4351

4452
The path component contains data, usually organized in hierarchical
4553
form, that, serves to identify a resource [URI > 3.3 Path](https://www.rfc-editor.org/info/rfc3986).
4654

47-
* Type: `uint8_t[]`. **REQUIRED**
48-
* Example:
49-
* `0xA` (10)
50-
* `/foo/bar`
55+
* Type: `string`. **REQUIRED**
56+
* Example: `/foo/bar`
5157
* Default: `/`
5258

5359
### HEADERS
@@ -68,7 +74,6 @@ The final data to be used for request receiver. Starts with `B\n`.
6874
* Message: `B\nlorem ipsum message`
6975
* Buffer: `['B', '\n', 0x1, 0x2, 0x3, 0x4]`
7076

71-
7277
## Middlewares
7378

7479
@TODO Explains what is a middleware and how its works

iot_protocol.cpp

Lines changed: 110 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ void IoTApp::runMiddleware(IoTRequest *request, int index = 0)
2020
this->middlewares.at(index)(request, &_next);
2121

2222
/* If is the last middleware */
23-
if(index == this->middlewares.size()-1) {
23+
if (index == this->middlewares.size() - 1)
24+
{
2425
/* Free memory */
25-
free(request->path);
26-
free(request->body);
26+
this->freeRequest(request);
2727
}
2828
}
2929

@@ -32,7 +32,78 @@ void IoTApp::listen(Client *client)
3232
this->clients.push_back(client);
3333
}
3434

35-
void IoTApp::resetClients() {
35+
uint16_t IoTApp::generateRequestId()
36+
{
37+
uint16_t id = (uint16_t)(millis() % 10000);
38+
if (this->requestResponse.find(id) != this->requestResponse.end() || id == 0)
39+
{
40+
return this->generateRequestId();
41+
}
42+
return id;
43+
}
44+
45+
IoTRequest *IoTApp::send(IoTRequest *request, IoTRequestResponse *requestResponse)
46+
{
47+
48+
request->version = IOT_VERSION;
49+
50+
if (request->id == 0)
51+
{
52+
request->id = this->generateRequestId();
53+
}
54+
55+
if (request->path == NULL)
56+
{
57+
request->path = static_cast<char *>(malloc(1 * sizeof(char) + 1));
58+
request->path[0] = '/';
59+
request->path[1] = '\0';
60+
}
61+
size_t pathLength = strlen(request->path);
62+
63+
String headers = "";
64+
for (auto header = request->headers.begin(); header != request->headers.end(); ++header)
65+
{
66+
headers += header->first + ":" + header->second + "\n";
67+
}
68+
69+
size_t dataLength = 1 + 1 + 1 + 2 + 1 /* (version+\n+method+id+\n) */ + pathLength + 1 /* (\n) */ + headers.length();
70+
71+
if (request->body != NULL)
72+
{
73+
dataLength += 1 + 1 /* (B+\n) */ + request->bodyLength;
74+
}
75+
76+
uint8_t *data = (uint8_t *)(malloc(dataLength * sizeof(uint8_t)));
77+
data[0] = request->id;
78+
data[1] = '\n';
79+
data[2] = static_cast<uint8_t>((char)request->method);
80+
data[3] = request->id >> 8; /* Id as Big Endian (MSB first) */
81+
data[4] = request->id - (data[3] << 8);
82+
data[5] = '\n';
83+
memcpy((data + 6), request->path, pathLength);
84+
size_t nextIndex = 6 + pathLength + 1;
85+
data[nextIndex] = '\n';
86+
nextIndex++;
87+
88+
if (headers.length() > 0)
89+
{
90+
memcpy((data + nextIndex), headers.c_str(), headers.length());
91+
nextIndex += (headers.length() + 1);
92+
}
93+
if (request->body != NULL)
94+
{
95+
data[nextIndex] = 'B';
96+
data[++nextIndex] = '\n';
97+
memcpy((data + nextIndex + 1), request->body, request->bodyLength);
98+
}
99+
100+
request->client->write(data, dataLength);
101+
102+
return request;
103+
}
104+
105+
void IoTApp::resetClients()
106+
{
36107
this->clients.clear();
37108
}
38109

@@ -42,9 +113,9 @@ void IoTApp::onData(Client *client, uint8_t *buffer, size_t bufLen)
42113
IoTRequest request = {
43114
1,
44115
EIoTMethod::SIGNAL,
116+
0,
45117
NULL,
46118
std::map<String, String>(),
47-
std::map<String, String>(),
48119
NULL,
49120
0,
50121
client};
@@ -60,38 +131,53 @@ void IoTApp::onData(Client *client, uint8_t *buffer, size_t bufLen)
60131
{
61132
indexN = indexOf(buffer, bufLen, '\n', indexStart);
62133

63-
uint8_t *bufferPartStart = buffer + indexStart;
134+
uint8_t *bufferPart = buffer + indexStart;
64135
size_t bufferPartLength = ((indexN == -1 || isBody) ? (bufLen + 1) : indexN) - indexStart;
65136

66-
uint8_t bufferPart[bufferPartLength];
67-
for (size_t i = 0; i < bufferPartLength; i++)
68-
{
69-
bufferPart[i] = bufferPartStart[i];
70-
}
137+
// uint8_t bufferPart[bufferPartLength];
138+
// for (size_t i = 0; i < bufferPartLength; i++)
139+
// {
140+
// bufferPart[i] = bufferPartStart[i];
141+
// }
71142

72143
// [ 0 \n 1 2 \n 3 4 5 \n 6 7 8 9]
73144
switch (foundN)
74145
{
75146
case 0:
76-
if(bufferPartLength > 1) {
147+
if (bufferPartLength > 1)
148+
{
77149
invalidRequest = true;
78150
continue;
79151
}
80152
request.version = static_cast<byte>((char)bufferPart[0]);
81153
break;
82154
case 1:
155+
/* Fix: ID = [\n, *] | [*, \n] | [\n,\n] */
156+
if (bufferPartLength != 3)
157+
{
158+
indexN = indexStart + 3;
159+
if (buffer[indexN] == ((uint8_t)(0xA)) /* (0xA = \n) */)
160+
{
161+
bufferPartLength = 3;
162+
}
163+
else
164+
{
165+
invalidRequest = true;
166+
continue;
167+
}
168+
}
169+
83170
request.method = static_cast<EIoTMethod>((char)bufferPart[0]);
171+
request.id = (bufferPart[1] << 8) + bufferPart[2];
84172
break;
85173
case 2:
86174
request.path = static_cast<char *>(malloc(bufferPartLength * sizeof(char) + 1));
87-
memcpy(request.path, bufferPartStart, bufferPartLength);
175+
memcpy(request.path, bufferPart, bufferPartLength);
88176
request.path[bufferPartLength] = '\0';
89-
/* @TODO: define params */
90177
break;
91178
default:
92179

93180
/* Headers */
94-
// const indexKeyValue = bufferPart.indexOf(":");
95181
int indexKeyValue = indexOf(bufferPart, bufferPartLength, ':');
96182
if (indexKeyValue > 0 && isBody == false)
97183
{
@@ -120,7 +206,7 @@ void IoTApp::onData(Client *client, uint8_t *buffer, size_t bufLen)
120206
if (isBody)
121207
{
122208
request.body = (uint8_t *)(malloc(bufferPartLength * sizeof(uint8_t) + 1));
123-
memcpy(request.body, bufferPartStart, bufferPartLength);
209+
memcpy(request.body, bufferPart, bufferPartLength);
124210
request.body[bufferPartLength] = '\0';
125211
request.bodyLength = bufferPartLength;
126212
isBody = false;
@@ -133,8 +219,8 @@ void IoTApp::onData(Client *client, uint8_t *buffer, size_t bufLen)
133219

134220
} while (indexN >= 0 && invalidRequest == false);
135221

136-
if (invalidRequest) return;
137-
222+
if (invalidRequest)
223+
return;
138224

139225
this->runMiddleware(&request);
140226
}
@@ -158,4 +244,10 @@ void IoTApp::loop()
158244
this->onData(client, buffer, (indexBuffer - 1));
159245
}
160246
}
247+
}
248+
249+
void IoTApp::freeRequest(IoTRequest *request)
250+
{
251+
free(request->path);
252+
free(request->body);
161253
}

iot_protocol.h

Lines changed: 61 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -16,54 +16,70 @@
1616

1717
#include "iot_helpers.h"
1818

19+
#define IOT_VERSION (byte)1
1920
#define IOT_PROTOCOL_MAX_READ_LENGTH 1024
2021

21-
enum class EIoTMethod : char
22-
{
23-
SIGNAL = 'S',
24-
REQUEST = 'R'
25-
};
26-
27-
enum class EIoTRequestPart : char
28-
{
29-
BODY = 'B',
30-
};
31-
32-
struct IoTRequest
33-
{
34-
byte version;
35-
EIoTMethod method;
36-
char* path;
37-
std::map<String, String> params;
38-
std::map<String, String> headers;
39-
uint8_t * body;
40-
size_t bodyLength;
41-
Client * client;
42-
};
43-
44-
typedef std::function<void(void)> Next;
22+
struct IoTRequest
23+
{
24+
byte version;
25+
EIoTMethod method;
26+
uint16_t id;
27+
char *path;
28+
std::map<String, String> headers;
4529

46-
typedef void (*IoTMiddleware)(IoTRequest *, Next*);
47-
48-
class IoTApp
49-
{
50-
private:
51-
std::vector<Client *> clients;
52-
void onData(Client* client, uint8_t* buffer, size_t bufLen);
53-
public:
54-
std::vector<IoTMiddleware> middlewares;
55-
56-
void use(IoTMiddleware middleware);
57-
58-
void runMiddleware(IoTRequest *request, int index);
59-
60-
void listen(Client *client);
61-
62-
void resetClients();
63-
64-
void loop();
65-
66-
};
30+
uint8_t *body;
31+
size_t bodyLength;
32+
Client *client;
33+
};
34+
35+
typedef std::function<void(void)> Next;
36+
typedef void (*IoTMiddleware)(IoTRequest *, Next *);
37+
38+
enum class EIoTMethod : char
39+
{
40+
SIGNAL = 'S',
41+
REQUEST = 'R',
42+
RESPONSE = 'r'
43+
};
44+
45+
enum class EIoTRequestPart : char
46+
{
47+
BODY = 'B',
48+
};
49+
50+
struct IoTRequestResponse
51+
{
52+
std::function<void(IoTRequest *response)> onResponse;
53+
std::function<void(IoTRequest *request)> onResponse;
54+
int timeout;
55+
};
56+
57+
class IoTApp
58+
{
59+
private:
60+
std::vector<Client *> clients;
61+
void onData(Client *client, uint8_t *buffer, size_t bufLen);
62+
std::map<uint16_t, IoTRequestResponse*> requestResponse;
63+
64+
public:
65+
std::vector<IoTMiddleware> middlewares;
66+
67+
/* Common methods */
68+
void use(IoTMiddleware middleware);
69+
void runMiddleware(IoTRequest *request, int index);
70+
void listen(Client *client);
71+
uint16_t generateRequestId();
72+
IoTRequest *signal(IoTRequest *request);
73+
IoTRequest *request(IoTRequest *request, IoTRequestResponse *requestResponse);
74+
IoTRequest *response(IoTRequest *request, uint8_t *body);
75+
IoTRequest *send(IoTRequest *request, IoTRequestResponse *requestResponse);
76+
77+
78+
/* Helpers methods */
79+
void resetClients();
80+
void loop();
81+
void freeRequest(IoTRequest * request);
82+
};
6783

6884
// #ifdef __cplusplus
6985
// }

0 commit comments

Comments
 (0)