Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9dc9374
Support hosted builds against Arduino-Emulator
MitchBradley Apr 4, 2026
a302812
Changed comments to address Copilot nitpicking
MitchBradley Apr 4, 2026
9f138a2
Changed cpp macros to c++ possibly-null classes, thanks willmmiles
MitchBradley Apr 5, 2026
704daee
locks in asyncsrv namespace, guarded by ASYNCSRV_USE_MUTEX
MitchBradley Apr 6, 2026
f13f005
HOST versions of logging.
MitchBradley Apr 6, 2026
4ab4d79
__unused -> __asyncws_unused
MitchBradley Apr 7, 2026
c41669f
More explicit formulation of ASYNCWEBSERVER_USE_MUTEX define
MitchBradley Apr 7, 2026
04d695e
Merge branch 'main' into HOSTmacro
mathieucarbou Apr 8, 2026
d09c360
ci(pre-commit): Apply automatic fixes
pre-commit-ci-lite[bot] Apr 8, 2026
d0c7e8d
Apply suggestion from @mathieucarbou
mathieucarbou Apr 8, 2026
5b72d9e
Fix compile sisue
mathieucarbou Apr 8, 2026
237dd64
Add CI for Arduino-Emulator
mathieucarbou Apr 8, 2026
4ccec50
Fix compilation issue where tcp_state enum type was not found
mathieucarbou Apr 8, 2026
ca7c83b
Add CI for Arduino-Emulator
mathieucarbou Apr 8, 2026
3ec0583
ci(pre-commit): Apply automatic fixes
pre-commit-ci-lite[bot] Apr 8, 2026
717925a
Fix Arduino Elumator CI
mathieucarbou Apr 8, 2026
ccdef5f
Move FPSTR in cpp
mathieucarbou Apr 8, 2026
6580dd1
Try fix CI on linux (works on mac)
mathieucarbou Apr 8, 2026
41e8e70
Project Structure Reorg: regrouping all examples under examples folder
mathieucarbou Apr 8, 2026
c610286
Merge branch 'main' into HOSTmacro
mathieucarbou Apr 8, 2026
c0619cb
Move arduino_emulator to examples folder
mathieucarbou Apr 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 11 additions & 34 deletions src/AsyncEventSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,19 +191,15 @@ AsyncEventSourceClient::AsyncEventSourceClient(AsyncWebServerRequest *request, A
}

AsyncEventSourceClient::~AsyncEventSourceClient() {
#ifdef ESP32
// Protect message queue access (size checks and modifications) which is not thread-safe.
std::lock_guard<std::recursive_mutex> lock(_lockmq);
#endif
lock_guard_type lock(_lockmq);
_messageQueue.clear();
close();
}

bool AsyncEventSourceClient::_queueMessage(const char *message, size_t len) {
#ifdef ESP32
// Protect message queue access (size checks and modifications) which is not thread-safe.
std::lock_guard<std::recursive_mutex> lock(_lockmq);
#endif
lock_guard_type lock(_lockmq);

if (_messageQueue.size() >= SSE_MAX_QUEUED_MESSAGES) {
async_ws_log_w("Event message queue overflow: discard message");
Expand Down Expand Up @@ -231,10 +227,8 @@ bool AsyncEventSourceClient::_queueMessage(const char *message, size_t len) {
}

bool AsyncEventSourceClient::_queueMessage(AsyncEvent_SharedData_t &&msg) {
#ifdef ESP32
// Protect message queue access (size checks and modifications) which is not thread-safe.
std::lock_guard<std::recursive_mutex> lock(_lockmq);
#endif
lock_guard_type lock(_lockmq);

if (_messageQueue.size() >= SSE_MAX_QUEUED_MESSAGES) {
async_ws_log_w("Event message queue overflow: discard message");
Expand All @@ -261,10 +255,8 @@ bool AsyncEventSourceClient::_queueMessage(AsyncEvent_SharedData_t &&msg) {
}

void AsyncEventSourceClient::_onAck(size_t len __attribute__((unused)), uint32_t time __attribute__((unused))) {
#ifdef ESP32
// Protect message queue access (size checks and modifications) which is not thread-safe.
std::lock_guard<std::recursive_mutex> lock(_lockmq);
#endif
lock_guard_type lock(_lockmq);

// adjust in-flight len
if (len < _inflight) {
Expand All @@ -289,10 +281,8 @@ void AsyncEventSourceClient::_onAck(size_t len __attribute__((unused)), uint32_t
}

void AsyncEventSourceClient::_onPoll() {
#ifdef ESP32
// Protect message queue access (size checks and modifications) which is not thread-safe.
std::lock_guard<std::recursive_mutex> lock(_lockmq);
#endif
lock_guard_type lock(_lockmq);
if (_messageQueue.size()) {
_runQueue();
}
Expand Down Expand Up @@ -373,10 +363,7 @@ void AsyncEventSource::_addClient(AsyncEventSourceClient *client) {
_connectcb(client);
}

#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
#endif

lock_guard_type lock(_client_queue_lock);
_clients.emplace_back(client);

_adjust_inflight_window();
Expand All @@ -386,9 +373,7 @@ void AsyncEventSource::_handleDisconnect(AsyncEventSourceClient *client) {
if (_disconnectcb) {
_disconnectcb(client);
}
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
#endif
lock_guard_type lock(_client_queue_lock);
for (auto i = _clients.begin(); i != _clients.end(); ++i) {
if (i->get() == client) {
_clients.erase(i);
Expand All @@ -402,9 +387,7 @@ void AsyncEventSource::close() {
// 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
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
#endif
lock_guard_type lock(_client_queue_lock);
for (const auto &c : _clients) {
if (c->connected()) {
/**
Expand All @@ -421,9 +404,7 @@ void AsyncEventSource::close() {
size_t AsyncEventSource::avgPacketsWaiting() const {
size_t aql = 0;
uint32_t nConnectedClients = 0;
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
#endif
lock_guard_type lock(_client_queue_lock);
for (const auto &c : _clients) {
if (c->connected()) {
aql += c->packetsWaiting();
Expand All @@ -435,9 +416,7 @@ size_t AsyncEventSource::avgPacketsWaiting() const {

AsyncEventSource::SendStatus AsyncEventSource::send(const char *message, const char *event, uint32_t id, uint32_t reconnect) {
AsyncEvent_SharedData_t shared_msg = std::make_shared<String>(generateEventMessage(message, event, id, reconnect));
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
#endif
lock_guard_type lock(_client_queue_lock);
size_t hits = 0;
size_t miss = 0;
for (const auto &c : _clients) {
Expand All @@ -453,9 +432,7 @@ AsyncEventSource::SendStatus AsyncEventSource::send(const char *message, const c
}

size_t AsyncEventSource::count() const {
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
#endif
lock_guard_type lock(_client_queue_lock);
size_t n_clients{0};
for (const auto &i : _clients) {
if (i->connected()) {
Expand Down
18 changes: 6 additions & 12 deletions src/AsyncEventSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

#include <Arduino.h>

#if defined(ESP32) || defined(LIBRETINY)
#if defined(ESP32) || defined(LIBRETINY) || defined(HOST)
#include <AsyncTCP.h>
#ifdef LIBRETINY
#ifdef round
Expand Down Expand Up @@ -136,9 +136,7 @@ class AsyncEventSourceClient {
size_t _inflight{0}; // num of unacknowledged bytes that has been written to socket buffer
size_t _max_inflight{SSE_MAX_INFLIGH}; // max num of unacknowledged bytes that could be written to socket buffer
std::list<AsyncEventSourceMessage> _messageQueue;
#ifdef ESP32
mutable std::recursive_mutex _lockmq;
#endif
mutable mutex_type _lockmq;
bool _queueMessage(const char *message, size_t len);
bool _queueMessage(AsyncEvent_SharedData_t &&msg);
void _runQueue();
Expand Down Expand Up @@ -205,9 +203,7 @@ class AsyncEventSourceClient {
return _lastId;
}
size_t packetsWaiting() const {
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_lockmq);
#endif
lock_guard_type lock(_lockmq);
return _messageQueue.size();
};

Expand Down Expand Up @@ -245,11 +241,9 @@ class AsyncEventSource : public AsyncWebHandler {
private:
String _url;
std::list<std::unique_ptr<AsyncEventSourceClient>> _clients;
#ifdef ESP32
// Same as for individual messages, protect mutations of _clients list
// since simultaneous access from different tasks is possible
mutable std::recursive_mutex _client_queue_lock;
#endif
mutable mutex_type _client_queue_lock;
ArEventHandlerFunction _connectcb = nullptr;
ArEventHandlerFunction _disconnectcb = nullptr;

Expand Down Expand Up @@ -331,11 +325,11 @@ class AsyncEventSourceResponse : public AsyncWebServerResponse {

public:
AsyncEventSourceResponse(AsyncEventSource *server);
void _respond(AsyncWebServerRequest *request);
void _respond(AsyncWebServerRequest *request) override;
size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time) override {
return 0;
};
bool _sourceValid() const {
bool _sourceValid() const override {
return true;
}
};
7 changes: 7 additions & 0 deletions src/AsyncWebServerLogging.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@
#define async_ws_log_d(format, ...) log_d(format, ##__VA_ARGS__)
#define async_ws_log_v(format, ...) log_v(format, ##__VA_ARGS__)

#elif defined(HOST)
Comment thread
mathieucarbou marked this conversation as resolved.
#define async_ws_log_e(format, ...)
#define async_ws_log_w(format, ...)
#define async_ws_log_i(format, ...)
#define async_ws_log_d(format, ...)
#define async_ws_log_v(format, ...)
Comment thread
mathieucarbou marked this conversation as resolved.

/**
* Raspberry Pi Pico specific configurations
*/
Expand Down
Loading
Loading