diff --git a/README.md b/README.md index 97abd49..b10865c 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubo - Remove filename after inline in Content-Disposition header according to RFC2183 - Depends on `mathieucarbou/Async TCP @ ^3.1.4` - Arduino 3 / ESP-IDF 5.1 compatibility +- Added all flavors of `binary()`, `text()`, `binaryAll()` and `textAll()` in `AsyncWebSocket` +- Added `setCloseClientOnQueueFull(bool)` which can be set on a client to either close the connection or discard messages but not close the connection when the queue is full ## Documentation diff --git a/docs/index.md b/docs/index.md index 97abd49..b10865c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -28,6 +28,8 @@ This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubo - Remove filename after inline in Content-Disposition header according to RFC2183 - Depends on `mathieucarbou/Async TCP @ ^3.1.4` - Arduino 3 / ESP-IDF 5.1 compatibility +- Added all flavors of `binary()`, `text()`, `binaryAll()` and `textAll()` in `AsyncWebSocket` +- Added `setCloseClientOnQueueFull(bool)` which can be set on a client to either close the connection or discard messages but not close the connection when the queue is full ## Documentation diff --git a/examples/CaptivePortal/CaptivePortal.ino b/examples/CaptivePortal/CaptivePortal.ino index 5681709..c06dccd 100644 --- a/examples/CaptivePortal/CaptivePortal.ino +++ b/examples/CaptivePortal/CaptivePortal.ino @@ -16,7 +16,7 @@ public: CaptiveRequestHandler() {} virtual ~CaptiveRequestHandler() {} - bool canHandle(AsyncWebServerRequest *request){ + bool canHandle(__unused AsyncWebServerRequest *request){ //request->addInterestingHeader("ANY"); return true; } diff --git a/examples/Filters/Filters.ino b/examples/Filters/Filters.ino index 218828a..90b6f19 100644 --- a/examples/Filters/Filters.ino +++ b/examples/Filters/Filters.ino @@ -18,7 +18,7 @@ class CaptiveRequestHandler : public AsyncWebHandler { CaptiveRequestHandler() {} virtual ~CaptiveRequestHandler() {} - bool canHandle(AsyncWebServerRequest* request) { + bool canHandle(__unused AsyncWebServerRequest* request) { // request->addInterestingHeader("ANY"); return true; } diff --git a/examples/StreamFiles/StreamConcat.h b/examples/StreamFiles/StreamConcat.h index ba95ebe..1a53f2c 100644 --- a/examples/StreamFiles/StreamConcat.h +++ b/examples/StreamFiles/StreamConcat.h @@ -6,8 +6,8 @@ class StreamConcat : public Stream { public: StreamConcat(Stream* s1, Stream* s2) : _s1(s1), _s2(s2) {} - size_t write(const uint8_t* p, size_t n) override { return 0; } - size_t write(uint8_t c) override { return 0; } + size_t write(__unused const uint8_t* p, __unused size_t n) override { return 0; } + size_t write(__unused uint8_t c) override { return 0; } void flush() override {} int available() override { return _s1->available() + _s2->available(); } diff --git a/library.json_ b/library.json_ index cc6cb9a..539ff5d 100644 --- a/library.json_ +++ b/library.json_ @@ -1,6 +1,6 @@ { "name": "ESP Async WebServer", - "version": "2.10.1", + "version": "2.10.4", "description": "Asynchronous HTTP and WebSocket Server Library for ESP32. Supports: WebSocket, SSE, Authentication, Arduino Json 7, File Upload, Static File serving, URL Rewrite, URL Redirect, etc.", "keywords": "http,async,websocket,webserver", "homepage": "https://github.com/mathieucarbou/ESPAsyncWebServer", diff --git a/library.properties b/library.properties index e6ca366..fc68a1c 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP Async WebServer -version=2.10.1 +version=2.10.4 author=Me-No-Dev maintainer=Mathieu Carbou sentence=Asynchronous HTTP and WebSocket Server Library for ESP32 diff --git a/platformio.ini b/platformio.ini index daf31e4..eff6677 100644 --- a/platformio.ini +++ b/platformio.ini @@ -18,8 +18,8 @@ monitor_filters = esp32_exception_decoder, log2file lib_dir = . ; src_dir = examples/CaptivePortal ; src_dir = examples/SimpleServer -; src_dir = examples/StreamFiles -src_dir = examples/Filters +src_dir = examples/StreamFiles +; src_dir = examples/Filters [env:arduino] platform = espressif32 diff --git a/src/AsyncJson.h b/src/AsyncJson.h index b2f6e2e..6774454 100644 --- a/src/AsyncJson.h +++ b/src/AsyncJson.h @@ -264,7 +264,7 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler { request->send(500); } } - virtual void handleUpload(AsyncWebServerRequest* request, const String& filename, size_t index, uint8_t* data, size_t len, bool final) override final { + virtual void handleUpload(__unused AsyncWebServerRequest* request, __unused const String& filename, __unused size_t index, __unused uint8_t* data, __unused size_t len, __unused bool final) override final { } virtual void handleBody(AsyncWebServerRequest* request, uint8_t* data, size_t len, size_t index, size_t total) override final { if (_onRequest) { diff --git a/src/AsyncWebSocket.cpp b/src/AsyncWebSocket.cpp index 787b52a..f231d23 100644 --- a/src/AsyncWebSocket.cpp +++ b/src/AsyncWebSocket.cpp @@ -461,13 +461,22 @@ void AsyncWebSocketClient::_queueMessage(std::shared_ptr> b if (_messageQueue.size() >= WS_MAX_QUEUED_MESSAGES) { l.unlock(); + if(closeWhenFull) + { #ifdef ESP8266 - ets_printf("AsyncWebSocketClient::_queueMessage: Too many messages queued, closing connection\n"); + ets_printf("AsyncWebSocketClient::_queueMessage: Too many messages queued: closing connection\n"); #else - log_e("Too many messages queued: closing connection"); + log_e("Too many messages queued: closing connection"); #endif - _status = WS_DISCONNECTED; - if (_client) _client->close(true); + _status = WS_DISCONNECTED; + if (_client) _client->close(true); + } else { +#ifdef ESP8266 + ets_printf("AsyncWebSocketClient::_queueMessage: Too many messages queued: discarding new message\n"); +#else + log_e("Too many messages queued: discarding new message"); +#endif + } return; } else @@ -954,21 +963,19 @@ void AsyncWebSocket::text(uint32_t id, const __FlashStringHelper *data) free(message); } } - -void AsyncWebSocket::textAll(AsyncWebSocketMessageBuffer * buffer) +void AsyncWebSocket::text(uint32_t id, AsyncWebSocketMessageBuffer *buffer) { if (buffer) { - textAll(std::move(buffer->_buffer)); - delete buffer; + text(id, std::move(buffer->_buffer)); + delete buffer; } } - -void AsyncWebSocket::textAll(std::shared_ptr> buffer) +void AsyncWebSocket::text(uint32_t id, std::shared_ptr> buffer) { - for (auto &c : _clients) - if (c.status() == WS_CONNECTED) - c.text(buffer); + if (AsyncWebSocketClient *c = client(id)) + c->text(buffer); } + void AsyncWebSocket::textAll(const uint8_t *message, size_t len) { textAll(makeSharedBuffer(message, len)); @@ -1005,6 +1012,20 @@ void AsyncWebSocket::textAll(const __FlashStringHelper *data) free(message); } } +void AsyncWebSocket::textAll(AsyncWebSocketMessageBuffer * buffer) +{ + if (buffer) { + textAll(std::move(buffer->_buffer)); + delete buffer; + } +} + +void AsyncWebSocket::textAll(std::shared_ptr> buffer) +{ + for (auto &c : _clients) + if (c.status() == WS_CONNECTED) + c.text(buffer); +} void AsyncWebSocket::binary(uint32_t id, const uint8_t *message, size_t len) { @@ -1034,27 +1055,24 @@ void AsyncWebSocket::binary(uint32_t id, const __FlashStringHelper *data, size_t free(message); } } - -void AsyncWebSocket::binaryAll(AsyncWebSocketMessageBuffer * buffer) +void AsyncWebSocket::binary(uint32_t id, AsyncWebSocketMessageBuffer *buffer) { if (buffer) { - binaryAll(std::move(buffer->_buffer)); + binary(id, std::move(buffer->_buffer)); delete buffer; } } - -void AsyncWebSocket::binaryAll(std::shared_ptr> buffer) +void AsyncWebSocket::binary(uint32_t id, std::shared_ptr> buffer) { - for (auto &c : _clients) - if (c.status() == WS_CONNECTED) - c.binary(buffer); + if (AsyncWebSocketClient *c = client(id)) + c->binary(buffer); } + void AsyncWebSocket::binaryAll(const uint8_t *message, size_t len) { binaryAll(makeSharedBuffer(message, len)); } - void AsyncWebSocket::binaryAll(const char *message, size_t len) { binaryAll((const uint8_t *)message, len); @@ -1078,6 +1096,19 @@ void AsyncWebSocket::binaryAll(const __FlashStringHelper *data, size_t len) free(message); } } +void AsyncWebSocket::binaryAll(AsyncWebSocketMessageBuffer * buffer) +{ + if (buffer) { + binaryAll(std::move(buffer->_buffer)); + delete buffer; + } +} +void AsyncWebSocket::binaryAll(std::shared_ptr> buffer) +{ + for (auto &c : _clients) + if (c.status() == WS_CONNECTED) + c.binary(buffer); +} size_t AsyncWebSocket::printf(uint32_t id, const char *format, ...){ AsyncWebSocketClient * c = client(id); diff --git a/src/AsyncWebSocket.h b/src/AsyncWebSocket.h index ac49d2b..ab182ea 100644 --- a/src/AsyncWebSocket.h +++ b/src/AsyncWebSocket.h @@ -137,6 +137,7 @@ class AsyncWebSocketClient { std::deque _controlQueue; std::deque _messageQueue; + bool closeWhenFull = true; uint8_t _pstate; AwsFrameInfo _pinfo; @@ -164,6 +165,27 @@ class AsyncWebSocketClient { const AsyncWebSocket *server() const { return _server; } AwsFrameInfo const &pinfo() const { return _pinfo; } + // - If "true" (default), the connection will be closed if the message queue is full. + // This is the default behavior in yubox-node-org, which is not silently discarding messages but instead closes the connection. + // The big issue with this behavior is that is can cause the UI to automatically re-create a new WS connection, which can be filled again, + // and so on, causing a resource exhaustion. + // + // - If "false", the incoming message will be discarded if the queue is full. + // This is the default behavior in the original ESPAsyncWebServer library from me-no-dev. + // This behavior allows the best performance at the expense of unreliable message delivery in case the queue is full (some messages may be lost). + // + // - In any case, when the queue is full, a message is logged. + // - IT is recommended to use the methods queueIsFull(), availableForWriteAll(), availableForWrite(clientId) to check if the queue is full before sending a message. + // + // Usage: + // - can be set in the onEvent listener when connecting (event type is: WS_EVT_CONNECT) + // + // Use cases:, + // - if using websocket to send logging messages, maybe some loss is acceptable. + // - But if using websocket to send UI update messages, maybe the connection should be closed and the UI redrawn. + void setCloseClientOnQueueFull(bool close) { closeWhenFull = close; } + bool willCloseClientOnQueueFull() const { return closeWhenFull; } + IPAddress remoteIP() const; uint16_t remotePort() const; @@ -257,28 +279,32 @@ class AsyncWebSocket: public AsyncWebHandler { void text(uint32_t id, const char *message); void text(uint32_t id, const String &message); void text(uint32_t id, const __FlashStringHelper *message); + void text(uint32_t id, AsyncWebSocketMessageBuffer *buffer); + void text(uint32_t id, std::shared_ptr> buffer); - void textAll(std::shared_ptr> buffer); void textAll(const uint8_t *message, size_t len); void textAll(const char * message, size_t len); void textAll(const char * message); void textAll(const String &message); - void textAll(const __FlashStringHelper *message); // need to convert + void textAll(const __FlashStringHelper *message); void textAll(AsyncWebSocketMessageBuffer *buffer); + void textAll(std::shared_ptr> buffer); void binary(uint32_t id, const uint8_t *message, size_t len); void binary(uint32_t id, const char *message, size_t len); void binary(uint32_t id, const char *message); void binary(uint32_t id, const String &message); void binary(uint32_t id, const __FlashStringHelper *message, size_t len); + void binary(uint32_t id, AsyncWebSocketMessageBuffer *buffer); + void binary(uint32_t id, std::shared_ptr> buffer); - void binaryAll(std::shared_ptr> buffer); void binaryAll(const uint8_t *message, size_t len); void binaryAll(const char *message, size_t len); void binaryAll(const char *message); void binaryAll(const String &message); void binaryAll(const __FlashStringHelper *message, size_t len); void binaryAll(AsyncWebSocketMessageBuffer *buffer); + void binaryAll(std::shared_ptr> buffer); size_t printf(uint32_t id, const char *format, ...) __attribute__ ((format (printf, 3, 4))); size_t printfAll(const char *format, ...) __attribute__ ((format (printf, 2, 3))); diff --git a/src/ESPAsyncWebServer.h b/src/ESPAsyncWebServer.h index 7667e20..8533df6 100644 --- a/src/ESPAsyncWebServer.h +++ b/src/ESPAsyncWebServer.h @@ -40,10 +40,10 @@ #error Platform not supported #endif -#define ASYNCWEBSERVER_VERSION "2.10.1" +#define ASYNCWEBSERVER_VERSION "2.10.4" #define ASYNCWEBSERVER_VERSION_MAJOR 2 #define ASYNCWEBSERVER_VERSION_MINOR 10 -#define ASYNCWEBSERVER_VERSION_REVISION 1 +#define ASYNCWEBSERVER_VERSION_REVISION 4 #define ASYNCWEBSERVER_FORK_mathieucarbou #ifdef ASYNCWEBSERVER_REGEX