2016-06-28 21:51:48 +03:00
|
|
|
/*
|
|
|
|
|
Asynchronous WebServer library for Espressif MCUs
|
|
|
|
|
|
|
|
|
|
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
License along with this library; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
|
*/
|
|
|
|
|
#include "Arduino.h"
|
2024-03-15 15:44:46 +01:00
|
|
|
#ifndef ESP8266
|
|
|
|
|
#include <rom/ets_sys.h>
|
|
|
|
|
#endif
|
2024-06-26 16:50:45 +09:00
|
|
|
#include "AsyncEventSource.h"
|
2016-06-28 21:51:48 +03:00
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
static String generateEventMessage(const char* message, const char* event, uint32_t id, uint32_t reconnect) {
|
2020-04-28 16:36:40 -04:00
|
|
|
String ev;
|
2016-06-29 19:29:39 +03:00
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
if (reconnect) {
|
2020-04-28 16:36:40 -04:00
|
|
|
ev += F("retry: ");
|
|
|
|
|
ev += reconnect;
|
|
|
|
|
ev += F("\r\n");
|
2016-06-29 19:29:39 +03:00
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
if (id) {
|
2020-04-28 16:36:40 -04:00
|
|
|
ev += F("id: ");
|
2016-06-29 21:26:41 +03:00
|
|
|
ev += String(id);
|
2020-04-28 16:36:40 -04:00
|
|
|
ev += F("\r\n");
|
2016-06-29 19:29:39 +03:00
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
if (event != NULL) {
|
2020-04-28 16:36:40 -04:00
|
|
|
ev += F("event: ");
|
2016-06-29 19:29:39 +03:00
|
|
|
ev += String(event);
|
2020-04-28 16:36:40 -04:00
|
|
|
ev += F("\r\n");
|
2016-06-29 19:29:39 +03:00
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
if (message != NULL) {
|
2016-06-29 19:29:39 +03:00
|
|
|
size_t messageLen = strlen(message);
|
2024-06-27 20:34:10 +02:00
|
|
|
char* lineStart = (char*)message;
|
|
|
|
|
char* lineEnd;
|
2016-06-29 19:29:39 +03:00
|
|
|
do {
|
2024-06-27 20:34:10 +02:00
|
|
|
char* nextN = strchr(lineStart, '\n');
|
|
|
|
|
char* nextR = strchr(lineStart, '\r');
|
|
|
|
|
if (nextN == NULL && nextR == NULL) {
|
|
|
|
|
size_t llen = ((char*)message + messageLen) - lineStart;
|
|
|
|
|
char* ldata = (char*)malloc(llen + 1);
|
|
|
|
|
if (ldata != NULL) {
|
2016-06-29 19:29:39 +03:00
|
|
|
memcpy(ldata, lineStart, llen);
|
|
|
|
|
ldata[llen] = 0;
|
2020-04-28 16:36:40 -04:00
|
|
|
ev += F("data: ");
|
2016-06-29 19:29:39 +03:00
|
|
|
ev += ldata;
|
2020-04-28 16:36:40 -04:00
|
|
|
ev += F("\r\n\r\n");
|
2016-06-29 19:29:39 +03:00
|
|
|
free(ldata);
|
|
|
|
|
}
|
2024-06-27 20:34:10 +02:00
|
|
|
lineStart = (char*)message + messageLen;
|
2016-06-29 19:29:39 +03:00
|
|
|
} else {
|
2024-06-27 20:34:10 +02:00
|
|
|
char* nextLine = NULL;
|
|
|
|
|
if (nextN != NULL && nextR != NULL) {
|
|
|
|
|
if (nextR < nextN) {
|
2016-06-29 19:29:39 +03:00
|
|
|
lineEnd = nextR;
|
2024-06-27 20:34:10 +02:00
|
|
|
if (nextN == (nextR + 1))
|
2016-06-29 19:29:39 +03:00
|
|
|
nextLine = nextN + 1;
|
|
|
|
|
else
|
|
|
|
|
nextLine = nextR + 1;
|
|
|
|
|
} else {
|
|
|
|
|
lineEnd = nextN;
|
2024-06-27 20:34:10 +02:00
|
|
|
if (nextR == (nextN + 1))
|
2016-06-29 19:29:39 +03:00
|
|
|
nextLine = nextR + 1;
|
|
|
|
|
else
|
|
|
|
|
nextLine = nextN + 1;
|
|
|
|
|
}
|
2024-06-27 20:34:10 +02:00
|
|
|
} else if (nextN != NULL) {
|
2016-06-29 19:29:39 +03:00
|
|
|
lineEnd = nextN;
|
|
|
|
|
nextLine = nextN + 1;
|
|
|
|
|
} else {
|
|
|
|
|
lineEnd = nextR;
|
|
|
|
|
nextLine = nextR + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t llen = lineEnd - lineStart;
|
2024-06-27 20:34:10 +02:00
|
|
|
char* ldata = (char*)malloc(llen + 1);
|
|
|
|
|
if (ldata != NULL) {
|
2016-06-29 19:29:39 +03:00
|
|
|
memcpy(ldata, lineStart, llen);
|
|
|
|
|
ldata[llen] = 0;
|
2020-04-28 16:36:40 -04:00
|
|
|
ev += F("data: ");
|
2016-06-29 19:29:39 +03:00
|
|
|
ev += ldata;
|
2020-04-28 16:36:40 -04:00
|
|
|
ev += F("\r\n");
|
2016-06-29 19:29:39 +03:00
|
|
|
free(ldata);
|
|
|
|
|
}
|
|
|
|
|
lineStart = nextLine;
|
2024-06-27 20:34:10 +02:00
|
|
|
if (lineStart == ((char*)message + messageLen))
|
2020-04-28 16:36:40 -04:00
|
|
|
ev += F("\r\n");
|
2016-06-29 19:29:39 +03:00
|
|
|
}
|
2024-06-27 20:34:10 +02:00
|
|
|
} while (lineStart < ((char*)message + messageLen));
|
2016-06-29 19:29:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ev;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-11 08:57:37 +00:00
|
|
|
// Message
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
AsyncEventSourceMessage::AsyncEventSourceMessage(const char* data, size_t len)
|
|
|
|
|
: _data(nullptr), _len(len), _sent(0), _acked(0) {
|
|
|
|
|
_data = (uint8_t*)malloc(_len + 1);
|
|
|
|
|
if (_data == nullptr) {
|
2017-03-11 08:57:37 +00:00
|
|
|
_len = 0;
|
|
|
|
|
} else {
|
|
|
|
|
memcpy(_data, data, len);
|
|
|
|
|
_data[_len] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AsyncEventSourceMessage::~AsyncEventSourceMessage() {
|
2024-06-27 20:34:10 +02:00
|
|
|
if (_data != NULL)
|
|
|
|
|
free(_data);
|
2017-03-11 08:57:37 +00:00
|
|
|
}
|
|
|
|
|
|
2017-04-06 11:11:48 +03:00
|
|
|
size_t AsyncEventSourceMessage::ack(size_t len, uint32_t time) {
|
2019-10-14 05:30:06 -03:00
|
|
|
(void)time;
|
2017-04-06 11:11:48 +03:00
|
|
|
// If the whole message is now acked...
|
2024-06-27 20:34:10 +02:00
|
|
|
if (_acked + len > _len) {
|
|
|
|
|
// Return the number of extra bytes acked (they will be carried on to the next message)
|
|
|
|
|
const size_t extra = _acked + len - _len;
|
|
|
|
|
_acked = _len;
|
|
|
|
|
return extra;
|
2017-03-11 08:57:37 +00:00
|
|
|
}
|
2017-04-06 11:11:48 +03:00
|
|
|
// Return that no extra bytes left.
|
|
|
|
|
_acked += len;
|
|
|
|
|
return 0;
|
2017-03-11 08:57:37 +00:00
|
|
|
}
|
|
|
|
|
|
2020-11-16 07:10:08 +01:00
|
|
|
// This could also return void as the return value is not used.
|
|
|
|
|
// Leaving as-is for compatibility...
|
2024-06-27 20:34:10 +02:00
|
|
|
size_t AsyncEventSourceMessage::send(AsyncClient* client) {
|
|
|
|
|
if (_sent >= _len) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
const size_t len_to_send = _len - _sent;
|
|
|
|
|
auto position = reinterpret_cast<const char*>(_data + _sent);
|
|
|
|
|
const size_t sent_now = client->write(position, len_to_send);
|
|
|
|
|
_sent += sent_now;
|
|
|
|
|
return sent_now;
|
2017-03-11 08:57:37 +00:00
|
|
|
}
|
|
|
|
|
|
2016-06-28 21:51:48 +03:00
|
|
|
// Client
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
AsyncEventSourceClient::AsyncEventSourceClient(AsyncWebServerRequest* request, AsyncEventSource* server) {
|
2016-06-28 21:51:48 +03:00
|
|
|
_client = request->client();
|
|
|
|
|
_server = server;
|
2016-06-29 21:21:10 +03:00
|
|
|
_lastId = 0;
|
2024-06-27 20:34:10 +02:00
|
|
|
if (request->hasHeader(F("Last-Event-ID")))
|
2020-04-28 16:36:40 -04:00
|
|
|
_lastId = atoi(request->getHeader(F("Last-Event-ID"))->value().c_str());
|
|
|
|
|
|
2016-09-23 21:56:28 +03:00
|
|
|
_client->setRxTimeout(0);
|
2016-06-28 21:51:48 +03:00
|
|
|
_client->onError(NULL, NULL);
|
2024-06-27 20:34:10 +02:00
|
|
|
_client->onAck([](void* r, AsyncClient* c, size_t len, uint32_t time) { (void)c; ((AsyncEventSourceClient*)(r))->_onAck(len, time); }, this);
|
|
|
|
|
_client->onPoll([](void* r, AsyncClient* c) { (void)c; ((AsyncEventSourceClient*)(r))->_onPoll(); }, this);
|
2016-06-28 21:51:48 +03:00
|
|
|
_client->onData(NULL, NULL);
|
2024-06-27 20:34:10 +02:00
|
|
|
_client->onTimeout([this](void* r, AsyncClient* c __attribute__((unused)), uint32_t time) { ((AsyncEventSourceClient*)(r))->_onTimeout(time); }, this);
|
|
|
|
|
_client->onDisconnect([this](void* r, AsyncClient* c) { ((AsyncEventSourceClient*)(r))->_onDisconnect(); delete c; }, this);
|
2017-03-11 08:57:37 +00:00
|
|
|
|
2016-06-28 21:51:48 +03:00
|
|
|
_server->_addClient(this);
|
|
|
|
|
delete request;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
AsyncEventSourceClient::~AsyncEventSourceClient() {
|
2024-06-26 16:50:45 +09:00
|
|
|
#ifdef ESP32
|
|
|
|
|
std::lock_guard<std::mutex> lock(_lockmq);
|
|
|
|
|
#endif
|
2024-06-26 17:55:58 +09:00
|
|
|
_messageQueue.clear();
|
2016-06-28 21:51:48 +03:00
|
|
|
close();
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
void AsyncEventSourceClient::_queueMessage(const char* message, size_t len) {
|
2024-06-26 16:50:45 +09:00
|
|
|
#ifdef ESP32
|
2024-06-27 20:34:10 +02:00
|
|
|
// length() is not thread-safe, thus acquiring the lock before this call..
|
2024-06-26 16:50:45 +09:00
|
|
|
std::lock_guard<std::mutex> lock(_lockmq);
|
|
|
|
|
#endif
|
2024-06-26 21:01:52 +09:00
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
if (_messageQueue.size() >= SSE_MAX_QUEUED_MESSAGES) {
|
2024-05-26 13:56:14 +02:00
|
|
|
#ifdef ESP8266
|
|
|
|
|
ets_printf(String(F("ERROR: Too many messages queued\n")).c_str());
|
|
|
|
|
#else
|
|
|
|
|
log_e("Too many messages queued: deleting message");
|
|
|
|
|
#endif
|
2024-06-27 20:34:10 +02:00
|
|
|
return;
|
2024-06-26 21:01:52 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_messageQueue.emplace_back(message, len);
|
|
|
|
|
// runqueue trigger when new messages added
|
2024-06-27 20:34:10 +02:00
|
|
|
if (_client->canSend()) {
|
2024-06-26 21:01:52 +09:00
|
|
|
_runQueue();
|
2019-10-17 09:05:13 +02:00
|
|
|
}
|
2017-03-11 08:57:37 +00:00
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
void AsyncEventSourceClient::_onAck(size_t len, uint32_t time) {
|
2024-06-26 16:50:45 +09:00
|
|
|
#ifdef ESP32
|
2020-11-16 05:06:21 +01:00
|
|
|
// Same here, acquiring the lock early
|
2024-06-26 16:50:45 +09:00
|
|
|
std::lock_guard<std::mutex> lock(_lockmq);
|
|
|
|
|
#endif
|
2024-06-27 20:34:10 +02:00
|
|
|
while (len && _messageQueue.size()) {
|
2024-06-26 21:01:52 +09:00
|
|
|
len = _messageQueue.front().ack(len, time);
|
2024-06-27 20:34:10 +02:00
|
|
|
if (_messageQueue.front().finished())
|
2024-06-26 17:55:58 +09:00
|
|
|
_messageQueue.pop_front();
|
2017-03-11 08:57:37 +00:00
|
|
|
}
|
|
|
|
|
_runQueue();
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
void AsyncEventSourceClient::_onPoll() {
|
2024-06-26 16:50:45 +09:00
|
|
|
#ifdef ESP32
|
|
|
|
|
// Same here, acquiring the lock early
|
|
|
|
|
std::lock_guard<std::mutex> lock(_lockmq);
|
|
|
|
|
#endif
|
2024-06-27 20:34:10 +02:00
|
|
|
if (_messageQueue.size()) {
|
2017-03-11 08:57:37 +00:00
|
|
|
_runQueue();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
void AsyncEventSourceClient::_onTimeout(uint32_t time __attribute__((unused))) {
|
2016-06-28 21:51:48 +03:00
|
|
|
_client->close(true);
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
void AsyncEventSourceClient::_onDisconnect() {
|
2016-06-28 21:51:48 +03:00
|
|
|
_client = NULL;
|
|
|
|
|
_server->_handleDisconnect(this);
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
void AsyncEventSourceClient::close() {
|
|
|
|
|
if (_client != NULL)
|
2016-06-29 21:44:33 +03:00
|
|
|
_client->close();
|
2016-06-28 21:51:48 +03:00
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
void AsyncEventSourceClient::write(const char* message, size_t len) {
|
|
|
|
|
if (!connected())
|
|
|
|
|
return;
|
2024-06-26 21:01:52 +09:00
|
|
|
_queueMessage(message, len);
|
2016-06-28 21:51:48 +03:00
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
void AsyncEventSourceClient::send(const char* message, const char* event, uint32_t id, uint32_t reconnect) {
|
|
|
|
|
if (!connected())
|
|
|
|
|
return;
|
2016-06-29 19:29:39 +03:00
|
|
|
String ev = generateEventMessage(message, event, id, reconnect);
|
2024-06-26 21:01:52 +09:00
|
|
|
_queueMessage(ev.c_str(), ev.length());
|
2017-03-11 08:57:37 +00:00
|
|
|
}
|
|
|
|
|
|
2020-11-16 05:06:21 +01:00
|
|
|
size_t AsyncEventSourceClient::packetsWaiting() const {
|
2024-06-26 16:50:45 +09:00
|
|
|
#ifdef ESP32
|
2024-06-27 20:34:10 +02:00
|
|
|
std::lock_guard<std::mutex> lock(_lockmq);
|
2024-06-26 16:50:45 +09:00
|
|
|
#endif
|
2024-06-27 20:34:10 +02:00
|
|
|
return _messageQueue.size();
|
2020-11-16 05:06:21 +01:00
|
|
|
}
|
2017-03-11 08:57:37 +00:00
|
|
|
|
2020-11-16 05:06:21 +01:00
|
|
|
void AsyncEventSourceClient::_runQueue() {
|
|
|
|
|
// Calls to this private method now already protected by _lockmq acquisition
|
|
|
|
|
// so no extra call of _lockmq.lock() here..
|
2024-06-27 20:34:10 +02:00
|
|
|
for (auto& i : _messageQueue) {
|
2024-06-26 21:01:52 +09:00
|
|
|
if (!i.sent())
|
|
|
|
|
i.send(_client);
|
2017-03-11 08:57:37 +00:00
|
|
|
}
|
2016-06-29 19:29:39 +03:00
|
|
|
}
|
|
|
|
|
|
2016-06-28 21:51:48 +03:00
|
|
|
// Handler
|
2024-06-27 20:34:10 +02:00
|
|
|
void AsyncEventSource::onConnect(ArEventHandlerFunction cb) {
|
2016-06-29 19:29:39 +03:00
|
|
|
_connectcb = cb;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
void AsyncEventSource::authorizeConnect(ArAuthorizeConnectHandler cb) {
|
2020-05-09 16:55:57 -04:00
|
|
|
_authorizeConnectHandler = cb;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
void AsyncEventSource::_addClient(AsyncEventSourceClient* client) {
|
2024-06-26 18:26:02 +09:00
|
|
|
if (!client)
|
|
|
|
|
return;
|
2024-06-26 16:50:45 +09:00
|
|
|
#ifdef ESP32
|
|
|
|
|
std::lock_guard<std::mutex> lock(_client_queue_lock);
|
|
|
|
|
#endif
|
2024-06-26 18:26:02 +09:00
|
|
|
_clients.emplace_back(client);
|
2024-06-27 20:34:10 +02:00
|
|
|
if (_connectcb)
|
2016-06-29 19:29:39 +03:00
|
|
|
_connectcb(client);
|
2016-06-28 21:51:48 +03:00
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
void AsyncEventSource::_handleDisconnect(AsyncEventSourceClient* client) {
|
2024-06-26 16:50:45 +09:00
|
|
|
#ifdef ESP32
|
|
|
|
|
std::lock_guard<std::mutex> lock(_client_queue_lock);
|
|
|
|
|
#endif
|
2024-06-27 20:34:10 +02:00
|
|
|
for (auto i = _clients.begin(); i != _clients.end(); ++i) {
|
2024-06-26 18:26:02 +09:00
|
|
|
if (i->get() == client)
|
|
|
|
|
_clients.erase(i);
|
|
|
|
|
}
|
2016-06-28 21:51:48 +03:00
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
void AsyncEventSource::close() {
|
2020-11-16 05:06:21 +01:00
|
|
|
// While the whole loop is not done, the linked list is locked and so the
|
|
|
|
|
// iterator should remain valid even when AsyncEventSource::_handleDisconnect()
|
|
|
|
|
// is called very early
|
2024-06-26 16:50:45 +09:00
|
|
|
#ifdef ESP32
|
|
|
|
|
std::lock_guard<std::mutex> lock(_client_queue_lock);
|
|
|
|
|
#endif
|
2024-06-27 20:34:10 +02:00
|
|
|
for (const auto& c : _clients) {
|
|
|
|
|
if (c->connected())
|
2016-06-28 21:51:48 +03:00
|
|
|
c->close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-02 14:33:18 +02:00
|
|
|
// pmb fix
|
|
|
|
|
size_t AsyncEventSource::avgPacketsWaiting() const {
|
2020-11-16 05:06:21 +01:00
|
|
|
size_t aql = 0;
|
|
|
|
|
uint32_t nConnectedClients = 0;
|
2024-06-26 16:50:45 +09:00
|
|
|
#ifdef ESP32
|
|
|
|
|
std::lock_guard<std::mutex> lock(_client_queue_lock);
|
|
|
|
|
#endif
|
2024-06-27 20:34:10 +02:00
|
|
|
if (!_clients.size())
|
|
|
|
|
return 0;
|
2024-06-26 18:26:02 +09:00
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
for (const auto& c : _clients) {
|
|
|
|
|
if (c->connected()) {
|
2020-11-16 05:06:21 +01:00
|
|
|
aql += c->packetsWaiting();
|
2019-10-02 14:33:18 +02:00
|
|
|
++nConnectedClients;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-27 20:34:10 +02:00
|
|
|
return ((aql) + (nConnectedClients / 2)) / (nConnectedClients); // round up
|
2019-10-02 14:33:18 +02:00
|
|
|
}
|
|
|
|
|
|
2020-11-16 05:06:21 +01:00
|
|
|
void AsyncEventSource::send(
|
2024-06-27 20:34:10 +02:00
|
|
|
const char* message, const char* event, uint32_t id, uint32_t reconnect) {
|
2016-06-29 19:29:39 +03:00
|
|
|
String ev = generateEventMessage(message, event, id, reconnect);
|
2024-06-26 16:50:45 +09:00
|
|
|
#ifdef ESP32
|
|
|
|
|
std::lock_guard<std::mutex> lock(_client_queue_lock);
|
|
|
|
|
#endif
|
2024-06-27 20:34:10 +02:00
|
|
|
for (const auto& c : _clients) {
|
|
|
|
|
if (c->connected()) {
|
2024-01-25 21:23:48 +01:00
|
|
|
c->write(ev.c_str(), ev.length());
|
2017-03-11 08:57:37 +00:00
|
|
|
}
|
2016-06-28 21:51:48 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-27 17:42:09 +02:00
|
|
|
size_t AsyncEventSource::count() const {
|
2024-06-26 16:50:45 +09:00
|
|
|
#ifdef ESP32
|
|
|
|
|
std::lock_guard<std::mutex> lock(_client_queue_lock);
|
|
|
|
|
#endif
|
2024-06-26 18:26:02 +09:00
|
|
|
size_t n_clients{0};
|
2024-06-27 20:34:10 +02:00
|
|
|
for (const auto& i : _clients)
|
2024-06-26 18:26:02 +09:00
|
|
|
if (i->connected())
|
|
|
|
|
++n_clients;
|
|
|
|
|
|
2020-11-16 05:06:21 +01:00
|
|
|
return n_clients;
|
2016-06-30 11:26:20 +03:00
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
bool AsyncEventSource::canHandle(AsyncWebServerRequest* request) {
|
|
|
|
|
if (request->method() != HTTP_GET || !request->url().equals(_url)) {
|
2016-06-28 21:51:48 +03:00
|
|
|
return false;
|
2019-06-22 17:59:46 +02:00
|
|
|
}
|
2020-04-28 16:36:40 -04:00
|
|
|
request->addInterestingHeader(F("Last-Event-ID"));
|
2020-05-09 16:55:57 -04:00
|
|
|
request->addInterestingHeader("Cookie");
|
2016-06-28 21:51:48 +03:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
void AsyncEventSource::handleRequest(AsyncWebServerRequest* request) {
|
|
|
|
|
if ((_username.length() && _password.length()) && !request->authenticate(_username.c_str(), _password.c_str())) {
|
2017-03-06 02:02:33 +08:00
|
|
|
return request->requestAuthentication();
|
2020-04-28 16:36:40 -04:00
|
|
|
}
|
2024-06-27 20:34:10 +02:00
|
|
|
if (_authorizeConnectHandler != NULL) {
|
|
|
|
|
if (!_authorizeConnectHandler(request)) {
|
2020-05-09 16:55:57 -04:00
|
|
|
return request->send(401);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-06-28 21:51:48 +03:00
|
|
|
request->send(new AsyncEventSourceResponse(this));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Response
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
AsyncEventSourceResponse::AsyncEventSourceResponse(AsyncEventSource* server) {
|
2016-06-28 21:51:48 +03:00
|
|
|
_server = server;
|
|
|
|
|
_code = 200;
|
2020-04-28 16:36:40 -04:00
|
|
|
_contentType = F("text/event-stream");
|
2016-06-28 21:51:48 +03:00
|
|
|
_sendContentLength = false;
|
2020-04-28 16:36:40 -04:00
|
|
|
addHeader(F("Cache-Control"), F("no-cache"));
|
|
|
|
|
addHeader(F("Connection"), F("keep-alive"));
|
2016-06-28 21:51:48 +03:00
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
void AsyncEventSourceResponse::_respond(AsyncWebServerRequest* request) {
|
2016-06-28 21:51:48 +03:00
|
|
|
String out = _assembleHead(request->version());
|
|
|
|
|
request->client()->write(out.c_str(), _headLength);
|
|
|
|
|
_state = RESPONSE_WAIT_ACK;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-27 20:34:10 +02:00
|
|
|
size_t AsyncEventSourceResponse::_ack(AsyncWebServerRequest* request, size_t len, uint32_t time __attribute__((unused))) {
|
|
|
|
|
if (len) {
|
2016-06-28 21:51:48 +03:00
|
|
|
new AsyncEventSourceClient(request, _server);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|