diff --git a/README.md b/README.md index 26f1f73..b10865c 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubo - 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 26f1f73..b10865c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -29,6 +29,7 @@ This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubo - 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/src/AsyncWebSocket.cpp b/src/AsyncWebSocket.cpp index 05dcf1a..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 diff --git a/src/AsyncWebSocket.h b/src/AsyncWebSocket.h index 1c5e314..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;