REDAC HybridController
Firmware for LUCIDAC/REDAC Teensy
Loading...
Searching...
No Matches
client.cpp
Go to the documentation of this file.
1#include "websockets/client.h"
2
3#include "websockets/common.h"
4#include "websockets/message.h"
5#include "websockets/tcp.h"
6#include <string.h>
7
8namespace websockets {
9WebsocketsClient::WebsocketsClient() : WebsocketsClient(std::make_shared<websockets::network::TcpClient>()) {
10 // Empty
11}
12
13FLASHMEM
14WebsocketsClient::WebsocketsClient(std::shared_ptr<network::TcpClient> client)
15 : _client(client), _endpoint(client), _connectionOpen(client->available()),
16 _messagesCallback([](WebsocketsClient &, WebsocketsMessage) {}),
17 _eventsCallback([](WebsocketsClient &, WebsocketsEvent, std::string) {}), _sendMode(SendMode_Normal) {
18 // Empty
19}
20
21FLASHMEM
22WebsocketsClient::WebsocketsClient(const WebsocketsClient &other)
23 : _client(other._client), _endpoint(other._endpoint), _connectionOpen(other._client->available()),
24 _messagesCallback(other._messagesCallback), _eventsCallback(other._eventsCallback),
25 _sendMode(other._sendMode) {
26
27 // delete other's client
28 const_cast<WebsocketsClient &>(other)._client = nullptr;
29 const_cast<WebsocketsClient &>(other)._connectionOpen = false;
30}
31
32FLASHMEM
33WebsocketsClient::WebsocketsClient(const WebsocketsClient &&other)
34 : _client(other._client), _endpoint(other._endpoint), _connectionOpen(other._client->available()),
35 _messagesCallback(other._messagesCallback), _eventsCallback(other._eventsCallback),
36 _sendMode(other._sendMode) {
37
38 // delete other's client
39 const_cast<WebsocketsClient &>(other)._client = nullptr;
40 const_cast<WebsocketsClient &>(other)._connectionOpen = false;
41}
42
43FLASHMEM
44WebsocketsClient &WebsocketsClient::operator=(const WebsocketsClient &other) {
45 // call endpoint's copy operator
46 _endpoint = other._endpoint;
47
48 // get callbacks and data from other
49 this->_client = other._client;
50 this->_messagesCallback = other._messagesCallback;
51 this->_eventsCallback = other._eventsCallback;
52 this->_connectionOpen = other._connectionOpen;
53 this->_sendMode = other._sendMode;
54
55 // delete other's client
56 const_cast<WebsocketsClient &>(other)._client = nullptr;
57 const_cast<WebsocketsClient &>(other)._connectionOpen = false;
58 return *this;
59}
60
61FLASHMEM
62WebsocketsClient &WebsocketsClient::operator=(const WebsocketsClient &&other) {
63 // call endpoint's copy operator
64 _endpoint = other._endpoint;
65
66 // get callbacks and data from other
67 this->_client = other._client;
68 this->_messagesCallback = other._messagesCallback;
69 this->_eventsCallback = other._eventsCallback;
70 this->_connectionOpen = other._connectionOpen;
71 this->_sendMode = other._sendMode;
72
73 // delete other's client
74 const_cast<WebsocketsClient &>(other)._client = nullptr;
75 const_cast<WebsocketsClient &>(other)._connectionOpen = false;
76 return *this;
77}
78
79FLASHMEM
80bool isWhitespace(char ch) { return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; }
81
82FLASHMEM
83bool isCaseInsensetiveEqual(const std::string lhs, const std::string rhs) {
84 if (lhs.size() != rhs.size())
85 return false;
86
87 for (size_t i = 0; i < lhs.size(); i++) {
88 char leftLowerCaseChar = lhs[i] >= 'A' && lhs[i] <= 'Z' ? lhs[i] - 'A' + 'a' : lhs[i];
89 char righerLowerCaseChar = rhs[i] >= 'A' && rhs[i] <= 'Z' ? rhs[i] - 'A' + 'a' : rhs[i];
90 if (leftLowerCaseChar != righerLowerCaseChar)
91 return false;
92 }
93
94 return true;
95}
96
97FLASHMEM
98bool doestStartsWith(std::string str, std::string prefix) {
99 if (str.size() < prefix.size())
100 return false;
101 for (size_t i = 0; i < prefix.size(); i++) {
102 if (str[i] != prefix[i])
103 return false;
104 }
105
106 return true;
107}
108
109FLASHMEM
110void WebsocketsClient::addHeader(const std::string key, const std::string value) {
111 _customHeaders.push_back({internals::fromInterfaceString(key), internals::fromInterfaceString(value)});
112}
113
114FLASHMEM
115void WebsocketsClient::onMessage(MessageCallback callback) { this->_messagesCallback = callback; }
116
117FLASHMEM
118void WebsocketsClient::onMessage(PartialMessageCallback callback) {
119 this->_messagesCallback = [callback](WebsocketsClient &, WebsocketsMessage msg) { callback(msg); };
120}
121
122FLASHMEM
123void WebsocketsClient::onEvent(EventCallback callback) { this->_eventsCallback = callback; }
124
125FLASHMEM
126void WebsocketsClient::onEvent(PartialEventCallback callback) {
127 this->_eventsCallback = [callback](WebsocketsClient &, WebsocketsEvent event, std::string data) {
128 callback(event, data);
129 };
130}
131
132FLASHMEM
133bool WebsocketsClient::poll() {
134 bool messageReceived = false;
135 while (available() && _endpoint.poll()) {
136 auto msg = _endpoint.recv();
137 if (msg.isEmpty()) {
138 continue;
139 }
140 messageReceived = true;
141
142 if (msg.isBinary() || msg.isText()) {
143 this->_messagesCallback(*this, std::move(msg));
144 } else if (msg.isContinuation()) {
145 // continuation messages will only be returned when policy is appropriate
146 this->_messagesCallback(*this, std::move(msg));
147 } else if (msg.isPing()) {
148 _handlePing(std::move(msg));
149 } else if (msg.isPong()) {
150 _handlePong(std::move(msg));
151 } else if (msg.isClose()) {
152 this->_connectionOpen = false;
153 _handleClose(std::move(msg));
154 }
155 }
156
157 return messageReceived;
158}
159
160WebsocketsMessage WebsocketsClient::readBlocking() {
161 while (available()) {
162#ifdef PLATFORM_DOES_NOT_SUPPORT_BLOCKING_READ
163 while (available() && _endpoint.poll() == false)
164 continue;
165#endif
166 auto msg = _endpoint.recv();
167 if (!msg.isEmpty())
168 return msg;
169 }
170 return {};
171}
172
173bool WebsocketsClient::send(const std::string &data) {
174 auto str = internals::fromInterfaceString(data);
175 return this->send(str.c_str(), str.size());
176}
177
178bool WebsocketsClient::send(const std::string &&data) {
179 auto str = internals::fromInterfaceString(data);
180 return this->send(str.c_str(), str.size());
181}
182
183bool WebsocketsClient::send(const char *data) { return this->send(data, strlen(data)); }
184
185FLASHMEM
186bool WebsocketsClient::send(const char *data, const size_t len) {
187 if (available()) {
188 // if in normal mode
189 if (this->_sendMode == SendMode_Normal) {
190 // send a normal message
191 return _endpoint.send(data, len, internals::ContentType::Text, true);
192 }
193 // if in streaming mode
194 else if (this->_sendMode == SendMode_Streaming) {
195 // send a continue frame
196 return _endpoint.send(data, len, internals::ContentType::Continuation, false);
197 }
198 }
199 return false;
200}
201
202bool WebsocketsClient::sendBinary(std::string data) {
203 auto str = internals::fromInterfaceString(data);
204 return this->sendBinary(str.c_str(), str.size());
205}
206
207FLASHMEM
208bool WebsocketsClient::sendBinary(const char *data, const size_t len) {
209 if (available()) {
210 // if in normal mode
211 if (this->_sendMode == SendMode_Normal) {
212 // send a normal message
213 return _endpoint.send(data, len, internals::ContentType::Binary, true);
214 }
215 // if in streaming mode
216 else if (this->_sendMode == SendMode_Streaming) {
217 // send a continue frame
218 return _endpoint.send(data, len, internals::ContentType::Continuation, false);
219 }
220 }
221 return false;
222}
223
224bool WebsocketsClient::stream(const std::string data) {
225 if (available() && this->_sendMode == SendMode_Normal) {
226 this->_sendMode = SendMode_Streaming;
227 return _endpoint.send(internals::fromInterfaceString(data), internals::ContentType::Text, false);
228 }
229 return false;
230}
231
232bool WebsocketsClient::streamBinary(const std::string data) {
233 if (available() && this->_sendMode == SendMode_Normal) {
234 this->_sendMode = SendMode_Streaming;
235 return _endpoint.send(internals::fromInterfaceString(data), internals::ContentType::Binary, false);
236 }
237 return false;
238}
239
240bool WebsocketsClient::end(const std::string data) {
241 if (available() && this->_sendMode == SendMode_Streaming) {
242 this->_sendMode = SendMode_Normal;
243 return _endpoint.send(internals::fromInterfaceString(data), internals::ContentType::Continuation, true);
244 }
245 return false;
246}
247
248void WebsocketsClient::setFragmentsPolicy(const FragmentsPolicy newPolicy) {
249 _endpoint.setFragmentsPolicy(newPolicy);
250}
251
252FLASHMEM
253bool WebsocketsClient::available(const bool activeTest) {
254 if (activeTest) {
255 _endpoint.ping("");
256 }
257
258 bool updatedConnectionOpen = this->_connectionOpen && this->_client && this->_client->available();
259
260 if (updatedConnectionOpen != this->_connectionOpen) {
261 _endpoint.close(CloseReason_AbnormalClosure);
262 this->_eventsCallback(*this, WebsocketsEvent::ConnectionClosed, "");
263 }
264
265 this->_connectionOpen = updatedConnectionOpen;
266 return this->_connectionOpen;
267}
268
269bool WebsocketsClient::ping(const std::string data) {
270 if (available()) {
271 return _endpoint.ping(internals::fromInterfaceString(data));
272 }
273 return false;
274}
275
276bool WebsocketsClient::pong(const std::string data) {
277 if (available()) {
278 return _endpoint.pong(internals::fromInterfaceString(data));
279 }
280 return false;
281}
282
283void WebsocketsClient::close(const CloseReason reason) {
284 if (available()) {
285 this->_connectionOpen = false;
286 _endpoint.close(reason);
287 _handleClose({});
288 }
289}
290
291CloseReason WebsocketsClient::getCloseReason() const { return _endpoint.getCloseReason(); }
292
293void WebsocketsClient::_handlePing(const WebsocketsMessage message) {
294 this->_eventsCallback(*this, WebsocketsEvent::GotPing, message.data());
295}
296
297void WebsocketsClient::_handlePong(const WebsocketsMessage message) {
298 this->_eventsCallback(*this, WebsocketsEvent::GotPong, message.data());
299}
300
301void WebsocketsClient::_handleClose(const WebsocketsMessage message) {
302 this->_eventsCallback(*this, WebsocketsEvent::ConnectionClosed, message.data());
303}
304
305WebsocketsClient::~WebsocketsClient() {
306 if (available()) {
307 this->close(CloseReason_GoingAway);
308 }
309}
310} // namespace websockets
FLASHMEM bool isCaseInsensetiveEqual(const std::string lhs, const std::string rhs)
Definition client.cpp:83
FLASHMEM bool isWhitespace(char ch)
Definition client.cpp:80
FLASHMEM bool doestStartsWith(std::string str, std::string prefix)
Definition client.cpp:98