From ec930047248aabe07b7645e250fef84e3a5dbe7b Mon Sep 17 00:00:00 2001 From: helgeerbe Date: Sat, 6 Jan 2024 22:42:34 +0100 Subject: [PATCH] Better handling of out of memory situations in live data websocket (onBattery) --- include/WebApi_ws_Huawei.h | 4 +++- include/WebApi_ws_battery.h | 3 +++ include/WebApi_ws_vedirect_live.h | 3 +++ src/WebApi_ws_Huawei.cpp | 26 ++++++++++++++++---------- src/WebApi_ws_battery.cpp | 21 +++++++++++++-------- src/WebApi_ws_vedirect_live.cpp | 23 ++++++++++++++--------- 6 files changed, 52 insertions(+), 28 deletions(-) diff --git a/include/WebApi_ws_Huawei.h b/include/WebApi_ws_Huawei.h index 8e61b7f7..3d1564e6 100644 --- a/include/WebApi_ws_Huawei.h +++ b/include/WebApi_ws_Huawei.h @@ -3,7 +3,7 @@ #include "ArduinoJson.h" #include -//#include +#include class WebApiWsHuaweiLiveClass { public: @@ -21,4 +21,6 @@ private: uint32_t _lastWsCleanup = 0; uint32_t _lastUpdateCheck = 0; + + std::mutex _mutex; }; \ No newline at end of file diff --git a/include/WebApi_ws_battery.h b/include/WebApi_ws_battery.h index 3454d71b..4a4da4b5 100644 --- a/include/WebApi_ws_battery.h +++ b/include/WebApi_ws_battery.h @@ -3,6 +3,7 @@ #include "ArduinoJson.h" #include +#include class WebApiWsBatteryLiveClass { public: @@ -21,4 +22,6 @@ private: uint32_t _lastWsCleanup = 0; uint32_t _lastUpdateCheck = 0; static constexpr uint16_t _responseSize = 1024 + 512; + + std::mutex _mutex; }; \ No newline at end of file diff --git a/include/WebApi_ws_vedirect_live.h b/include/WebApi_ws_vedirect_live.h index 3797b9b0..f914c592 100644 --- a/include/WebApi_ws_vedirect_live.h +++ b/include/WebApi_ws_vedirect_live.h @@ -4,6 +4,7 @@ #include "ArduinoJson.h" #include #include +#include class WebApiWsVedirectLiveClass { public: @@ -23,4 +24,6 @@ private: uint32_t _lastWsCleanup = 0; uint32_t _dataAgeMillis = 0; static constexpr uint16_t _responseSize = 1024 + 128; + + std::mutex _mutex; }; \ No newline at end of file diff --git a/src/WebApi_ws_Huawei.cpp b/src/WebApi_ws_Huawei.cpp index 128d4b0c..17449655 100644 --- a/src/WebApi_ws_Huawei.cpp +++ b/src/WebApi_ws_Huawei.cpp @@ -7,6 +7,7 @@ #include "Configuration.h" #include "Huawei_can.h" #include "MessageOutput.h" +#include "Utils.h" #include "WebApi.h" #include "defaults.h" @@ -50,16 +51,15 @@ void WebApiWsHuaweiLiveClass::loop() _lastUpdateCheck = millis(); try { - String buffer; - // free JsonDocument as soon as possible - { - DynamicJsonDocument root(1024); + std::lock_guard lock(_mutex); + DynamicJsonDocument root(1024); + if (Utils::checkJsonAlloc(root, __FUNCTION__, __LINE__)) { JsonVariant var = root; generateJsonResponse(var); - serializeJson(root, buffer); - } - if (buffer) { + String buffer; + serializeJson(root, buffer); + if (Configuration.get().Security.AllowReadonly) { _ws.setAuthentication("", ""); } else { @@ -69,7 +69,9 @@ void WebApiWsHuaweiLiveClass::loop() _ws.textAll(buffer); } } catch (std::bad_alloc& bad_alloc) { - MessageOutput.printf("Calling /api/livedata/status has temporarily run out of resources. Reason: \"%s\".\r\n", bad_alloc.what()); + MessageOutput.printf("Calling /api/huaweilivedata/status has temporarily run out of resources. Reason: \"%s\".\r\n", bad_alloc.what()); + } catch (const std::exception& exc) { + MessageOutput.printf("Unknown exception in /api/huaweilivedata/status. Reason: \"%s\".\r\n", exc.what()); } } @@ -122,15 +124,19 @@ void WebApiWsHuaweiLiveClass::onLivedataStatus(AsyncWebServerRequest* request) return; } try { + std::lock_guard lock(_mutex); AsyncJsonResponse* response = new AsyncJsonResponse(false, 1024U); auto& root = response->getRoot(); + generateJsonResponse(root); response->setLength(); request->send(response); } catch (std::bad_alloc& bad_alloc) { - MessageOutput.printf("Calling /api/livedata/status has temporarily run out of resources. Reason: \"%s\".\r\n", bad_alloc.what()); - + MessageOutput.printf("Calling /api/huaweilivedata/status has temporarily run out of resources. Reason: \"%s\".\r\n", bad_alloc.what()); + WebApi.sendTooManyRequests(request); + } catch (const std::exception& exc) { + MessageOutput.printf("Unknown exception in /api/huaweilivedata/status. Reason: \"%s\".\r\n", exc.what()); WebApi.sendTooManyRequests(request); } } \ No newline at end of file diff --git a/src/WebApi_ws_battery.cpp b/src/WebApi_ws_battery.cpp index 3a169fbc..f3ee725d 100644 --- a/src/WebApi_ws_battery.cpp +++ b/src/WebApi_ws_battery.cpp @@ -9,6 +9,7 @@ #include "MessageOutput.h" #include "WebApi.h" #include "defaults.h" +#include "Utils.h" WebApiWsBatteryLiveClass::WebApiWsBatteryLiveClass() : _ws("/batterylivedata") @@ -48,16 +49,15 @@ void WebApiWsBatteryLiveClass::loop() _lastUpdateCheck = millis(); try { - String buffer; - // free JsonDocument as soon as possible - { - DynamicJsonDocument root(_responseSize); + std::lock_guard lock(_mutex); + DynamicJsonDocument root(_responseSize); + if (Utils::checkJsonAlloc(root, __FUNCTION__, __LINE__)) { JsonVariant var = root; generateJsonResponse(var); - serializeJson(root, buffer); - } - if (buffer) { + String buffer; + serializeJson(root, buffer); + if (Configuration.get().Security.AllowReadonly) { _ws.setAuthentication("", ""); } else { @@ -68,6 +68,8 @@ void WebApiWsBatteryLiveClass::loop() } } catch (std::bad_alloc& bad_alloc) { MessageOutput.printf("Calling /api/batterylivedata/status has temporarily run out of resources. Reason: \"%s\".\r\n", bad_alloc.what()); + } catch (const std::exception& exc) { + MessageOutput.printf("Unknown exception in /api/batterylivedata/status. Reason: \"%s\".\r\n", exc.what()); } } @@ -91,6 +93,7 @@ void WebApiWsBatteryLiveClass::onLivedataStatus(AsyncWebServerRequest* request) return; } try { + std::lock_guard lock(_mutex); AsyncJsonResponse* response = new AsyncJsonResponse(false, _responseSize); auto& root = response->getRoot(); generateJsonResponse(root); @@ -99,7 +102,9 @@ void WebApiWsBatteryLiveClass::onLivedataStatus(AsyncWebServerRequest* request) request->send(response); } catch (std::bad_alloc& bad_alloc) { MessageOutput.printf("Calling /api/batterylivedata/status has temporarily run out of resources. Reason: \"%s\".\r\n", bad_alloc.what()); - + WebApi.sendTooManyRequests(request); + } catch (const std::exception& exc) { + MessageOutput.printf("Unknown exception in /api/batterylivedata/status. Reason: \"%s\".\r\n", exc.what()); WebApi.sendTooManyRequests(request); } } \ No newline at end of file diff --git a/src/WebApi_ws_vedirect_live.cpp b/src/WebApi_ws_vedirect_live.cpp index f89e7ecf..b353f4a6 100644 --- a/src/WebApi_ws_vedirect_live.cpp +++ b/src/WebApi_ws_vedirect_live.cpp @@ -6,6 +6,7 @@ #include "AsyncJson.h" #include "Configuration.h" #include "MessageOutput.h" +#include "Utils.h" #include "WebApi.h" #include "defaults.h" #include "PowerLimiter.h" @@ -55,16 +56,15 @@ void WebApiWsVedirectLiveClass::loop() if (millis() - _lastWsPublish > (10 * 1000) || lastDataAgeMillis > _dataAgeMillis) { try { - String buffer; - // free JsonDocument as soon as possible - { - DynamicJsonDocument root(_responseSize); + std::lock_guard lock(_mutex); + DynamicJsonDocument root(_responseSize); + if (Utils::checkJsonAlloc(root, __FUNCTION__, __LINE__)) { JsonVariant var = root; generateJsonResponse(var); + + String buffer; serializeJson(root, buffer); - } - - if (buffer) { + if (Configuration.get().Security.AllowReadonly) { _ws.setAuthentication("", ""); } else { @@ -76,6 +76,8 @@ void WebApiWsVedirectLiveClass::loop() } catch (std::bad_alloc& bad_alloc) { MessageOutput.printf("Calling /api/vedirectlivedata/status has temporarily run out of resources. Reason: \"%s\".\r\n", bad_alloc.what()); + } catch (const std::exception& exc) { + MessageOutput.printf("Unknown exception in /api/vedirectlivedata/status. Reason: \"%s\".\r\n", exc.what()); } _lastWsPublish = millis(); @@ -168,6 +170,7 @@ void WebApiWsVedirectLiveClass::onLivedataStatus(AsyncWebServerRequest* request) return; } try { + std::lock_guard lock(_mutex); AsyncJsonResponse* response = new AsyncJsonResponse(false, _responseSize); auto& root = response->getRoot(); @@ -177,8 +180,10 @@ void WebApiWsVedirectLiveClass::onLivedataStatus(AsyncWebServerRequest* request) request->send(response); } catch (std::bad_alloc& bad_alloc) { - MessageOutput.printf("Calling /api/livedata/status has temporarily run out of resources. Reason: \"%s\".\r\n", bad_alloc.what()); - + MessageOutput.printf("Calling /api/vedirectlivedata/status has temporarily run out of resources. Reason: \"%s\".\r\n", bad_alloc.what()); + WebApi.sendTooManyRequests(request); + } catch (const std::exception& exc) { + MessageOutput.printf("Unknown exception in /api/vedirectlivedata/status. Reason: \"%s\".\r\n", exc.what()); WebApi.sendTooManyRequests(request); } } \ No newline at end of file