memory optimizations

This commit is contained in:
Proddy
2024-02-05 09:38:11 +01:00
parent 738d9b1d94
commit 253adfeb45
7 changed files with 33 additions and 182 deletions

View File

@@ -32,7 +32,7 @@
"@types/imagemin": "^8.0.5", "@types/imagemin": "^8.0.5",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/node": "^20.11.16", "@types/node": "^20.11.16",
"@types/react": "^18.2.52", "@types/react": "^18.2.53",
"@types/react-dom": "^18.2.18", "@types/react-dom": "^18.2.18",
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
"alova": "^2.17.0", "alova": "^2.17.0",

View File

@@ -1670,14 +1670,14 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/react@npm:^18.2.52": "@types/react@npm:^18.2.53":
version: 18.2.52 version: 18.2.53
resolution: "@types/react@npm:18.2.52" resolution: "@types/react@npm:18.2.53"
dependencies: dependencies:
"@types/prop-types": "npm:*" "@types/prop-types": "npm:*"
"@types/scheduler": "npm:*" "@types/scheduler": "npm:*"
csstype: "npm:^3.0.2" csstype: "npm:^3.0.2"
checksum: 10/0ab90a37fd82028c3559f18ce50790d01b262589a2ea49d014d8888291f47d9c91e65cb7db031a3e5d58818cb5376577afb4b593068473abfd0c695fa7e6b7c4 checksum: 10/9a518aef07c6bb743aa18a2aea7f618d4e7c9e44e14d25119d2e255c48e68ecd901ede8b4eaf22ffe4f52c1ff85e11634ec75e73dcfc0719cc52269629f13d69
languageName: node languageName: node
linkType: hard linkType: hard
@@ -1859,7 +1859,7 @@ __metadata:
"@types/imagemin": "npm:^8.0.5" "@types/imagemin": "npm:^8.0.5"
"@types/lodash-es": "npm:^4.17.12" "@types/lodash-es": "npm:^4.17.12"
"@types/node": "npm:^20.11.16" "@types/node": "npm:^20.11.16"
"@types/react": "npm:^18.2.52" "@types/react": "npm:^18.2.53"
"@types/react-dom": "npm:^18.2.18" "@types/react-dom": "npm:^18.2.18"
"@types/react-router-dom": "npm:^5.3.3" "@types/react-router-dom": "npm:^5.3.3"
"@typescript-eslint/eslint-plugin": "npm:^6.20.0" "@typescript-eslint/eslint-plugin": "npm:^6.20.0"

View File

@@ -1,23 +0,0 @@
{
"name": "AsyncTCP-esphome",
"description": "Asynchronous TCP Library for ESP32",
"keywords": "async,tcp",
"authors": {
"name": "Hristo Gochkov",
"maintainer": true
},
"repository": {
"type": "git",
"url": "https://github.com/esphome/AsyncTCP.git"
},
"version": "2.1.1",
"license": "LGPL-3.0",
"frameworks": "arduino",
"platforms": [
"espressif32",
"libretiny"
],
"build": {
"libCompatMode": 2
}
}

View File

@@ -1,43 +0,0 @@
{
"name": "ESP Async WebServer",
"version": "2.6.1",
"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",
"repository": {
"type": "git",
"url": "https://github.com/mathieucarbou/ESPAsyncWebServer.git"
},
"authors": [
{
"name": "Hristo Gochkov"
},
{
"name": "Mathieu Carbou",
"maintainer": true
}
],
"license": "LGPL-3.0",
"frameworks": "arduino",
"platforms": [
"espressif32"
],
"dependencies": [
{
"owner": "esphome",
"name": "AsyncTCP-esphome",
"version": "^2.1.1",
"platforms": "espressif32"
}
],
"export": {
"include": [
"examples",
"src",
"library.json",
"library.properties",
"LICENSE",
"README.md"
]
}
}

View File

@@ -38,18 +38,8 @@
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <Print.h> #include <Print.h>
#if ARDUINOJSON_VERSION_MAJOR == 6
#ifndef DYNAMIC_JSON_DOCUMENT_SIZE
#define DYNAMIC_JSON_DOCUMENT_SIZE 1024
#endif
#endif
constexpr const char * JSON_MIMETYPE = "application/json"; constexpr const char * JSON_MIMETYPE = "application/json";
/*
* Json Response
* */
class ChunkPrint : public Print { class ChunkPrint : public Print {
private: private:
uint8_t * _destination; uint8_t * _destination;
@@ -129,40 +119,11 @@ class MsgpackAsyncJsonResponse : public AsyncAbstractResponse {
class AsyncJsonResponse : public AsyncAbstractResponse { class AsyncJsonResponse : public AsyncAbstractResponse {
protected: protected:
#if ARDUINOJSON_VERSION_MAJOR == 5
DynamicJsonBuffer _jsonBuffer;
#elif ARDUINOJSON_VERSION_MAJOR == 6
DynamicJsonDocument _jsonBuffer;
#else
JsonDocument _jsonBuffer; JsonDocument _jsonBuffer;
#endif JsonVariant _root;
bool _isValid;
JsonVariant _root;
bool _isValid;
public: public:
#if ARDUINOJSON_VERSION_MAJOR == 5
AsyncJsonResponse(bool isArray = false)
: _isValid{false} {
_code = 200;
_contentType = JSON_MIMETYPE;
if (isArray)
_root = _jsonBuffer.createArray();
else
_root = _jsonBuffer.createObject();
}
#elif ARDUINOJSON_VERSION_MAJOR == 6
AsyncJsonResponse(bool isArray = false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE)
: _jsonBuffer(maxJsonBufferSize)
, _isValid{false} {
_code = 200;
_contentType = JSON_MIMETYPE;
if (isArray)
_root = _jsonBuffer.createNestedArray();
else
_root = _jsonBuffer.createNestedObject();
}
#else
AsyncJsonResponse(bool isArray = false) AsyncJsonResponse(bool isArray = false)
: _isValid{false} { : _isValid{false} {
_code = 200; _code = 200;
@@ -172,7 +133,6 @@ class AsyncJsonResponse : public AsyncAbstractResponse {
else else
_root = _jsonBuffer.add<JsonObject>(); _root = _jsonBuffer.add<JsonObject>();
} }
#endif
~AsyncJsonResponse() { ~AsyncJsonResponse() {
} }
@@ -183,11 +143,7 @@ class AsyncJsonResponse : public AsyncAbstractResponse {
return _isValid; return _isValid;
} }
size_t setLength() { size_t setLength() {
#if ARDUINOJSON_VERSION_MAJOR == 5
_contentLength = _root.measureLength();
#else
_contentLength = measureJson(_root); _contentLength = measureJson(_root);
#endif
if (_contentLength) { if (_contentLength) {
_isValid = true; _isValid = true;
@@ -201,33 +157,18 @@ class AsyncJsonResponse : public AsyncAbstractResponse {
size_t _fillBuffer(uint8_t * data, size_t len) { size_t _fillBuffer(uint8_t * data, size_t len) {
ChunkPrint dest(data, _sentLength, len); ChunkPrint dest(data, _sentLength, len);
#if ARDUINOJSON_VERSION_MAJOR == 5
_root.printTo(dest);
#else
serializeJson(_root, dest); serializeJson(_root, dest);
#endif
return len; return len;
} }
}; };
class PrettyAsyncJsonResponse : public AsyncJsonResponse { class PrettyAsyncJsonResponse : public AsyncJsonResponse {
public: public:
#if ARDUINOJSON_VERSION_MAJOR == 6
PrettyAsyncJsonResponse(bool isArray = false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE)
: AsyncJsonResponse{isArray, maxJsonBufferSize} {
}
#else
PrettyAsyncJsonResponse(bool isArray = false) PrettyAsyncJsonResponse(bool isArray = false)
: AsyncJsonResponse{isArray} { : AsyncJsonResponse{isArray} {
} }
#endif
size_t setLength() { size_t setLength() {
#if ARDUINOJSON_VERSION_MAJOR == 5
_contentLength = _root.measurePrettyLength();
#else
_contentLength = measureJsonPretty(_root); _contentLength = measureJsonPretty(_root);
#endif
if (_contentLength) { if (_contentLength) {
_isValid = true; _isValid = true;
} }
@@ -235,11 +176,7 @@ class PrettyAsyncJsonResponse : public AsyncJsonResponse {
} }
size_t _fillBuffer(uint8_t * data, size_t len) { size_t _fillBuffer(uint8_t * data, size_t len) {
ChunkPrint dest(data, _sentLength, len); ChunkPrint dest(data, _sentLength, len);
#if ARDUINOJSON_VERSION_MAJOR == 5
_root.prettyPrintTo(dest);
#else
serializeJsonPretty(_root, dest); serializeJsonPretty(_root, dest);
#endif
return len; return len;
} }
}; };
@@ -253,28 +190,15 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
WebRequestMethodComposite _method; WebRequestMethodComposite _method;
ArJsonRequestHandlerFunction _onRequest; ArJsonRequestHandlerFunction _onRequest;
size_t _contentLength; size_t _contentLength;
#if ARDUINOJSON_VERSION_MAJOR == 6 size_t _maxContentLength;
const size_t maxJsonBufferSize;
#endif
size_t _maxContentLength;
public: public:
#if ARDUINOJSON_VERSION_MAJOR == 6
AsyncCallbackJsonWebHandler(const String & uri, ArJsonRequestHandlerFunction onRequest, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE)
: _uri(uri)
, _method(HTTP_POST | HTTP_PUT | HTTP_PATCH)
, _onRequest(onRequest)
, maxJsonBufferSize(maxJsonBufferSize)
, _maxContentLength(16384) {
}
#else
AsyncCallbackJsonWebHandler(const String & uri, ArJsonRequestHandlerFunction onRequest) AsyncCallbackJsonWebHandler(const String & uri, ArJsonRequestHandlerFunction onRequest)
: _uri(uri) : _uri(uri)
, _method(HTTP_POST | HTTP_PUT | HTTP_PATCH) , _method(HTTP_GET | HTTP_POST | HTTP_PUT | HTTP_PATCH)
, _onRequest(onRequest) , _onRequest(onRequest)
, _maxContentLength(16384) { , _maxContentLength(16384) {
} }
#endif
void setMethod(WebRequestMethodComposite method) { void setMethod(WebRequestMethodComposite method) {
_method = method; _method = method;
@@ -286,6 +210,7 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
_onRequest = fn; _onRequest = fn;
} }
virtual bool canHandle(AsyncWebServerRequest * request) override final { virtual bool canHandle(AsyncWebServerRequest * request) override final {
if (!_onRequest) if (!_onRequest)
return false; return false;
@@ -305,28 +230,17 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
virtual void handleRequest(AsyncWebServerRequest * request) override final { virtual void handleRequest(AsyncWebServerRequest * request) override final {
if (_onRequest) { if (_onRequest) {
JsonVariant json; // empty variant
if (request->_tempObject != NULL) { if (request->_tempObject != NULL) {
#if ARDUINOJSON_VERSION_MAJOR == 5
DynamicJsonBuffer jsonBuffer;
JsonVariant json = jsonBuffer.parse((uint8_t *)(request->_tempObject));
if (json.success()) {
#elif ARDUINOJSON_VERSION_MAJOR == 6
DynamicJsonDocument jsonBuffer(this->maxJsonBufferSize);
DeserializationError error = deserializeJson(jsonBuffer, (uint8_t *)(request->_tempObject));
if (!error) {
JsonVariant json = jsonBuffer.as<JsonVariant>();
#else
JsonDocument jsonBuffer; JsonDocument jsonBuffer;
DeserializationError error = deserializeJson(jsonBuffer, (uint8_t *)(request->_tempObject)); DeserializationError error = deserializeJson(jsonBuffer, (uint8_t *)(request->_tempObject));
if (!error) { if (!error) {
JsonVariant json = jsonBuffer.as<JsonVariant>(); json = jsonBuffer.as<JsonVariant>();
#endif
_onRequest(request, json); _onRequest(request, json);
return; return;
} }
} }
request->send(_contentLength > _maxContentLength ? 413 : 400); _onRequest(request, json);
} else { } else {
request->send(500); request->send(500);
} }

View File

@@ -34,21 +34,19 @@ class HttpEndpoint {
, _stateUpdater(stateUpdater) , _stateUpdater(stateUpdater)
, _statefulService(statefulService) { , _statefulService(statefulService) {
// Create the GET and POST endpoints // Create the GET and POST endpoints
// We can't use HTTP_ANY and process one a single endpoint due to the way the ESPAsyncWebServer library works POSThandler = new AsyncCallbackJsonWebHandler(servicePath,
// Could also use server->on() but this is more efficient securityManager->wrapCallback(
[this](AsyncWebServerRequest * request, JsonVariant json) {
// create the GET //
GEThandler = new AsyncCallbackWebHandler(); if (request->method() == HTTP_GET) {
GEThandler->setUri(servicePath); fetchSettings(request);
GEThandler->setMethod(HTTP_GET); } else if (request->method() == HTTP_POST) {
GEThandler->onRequest(securityManager->wrapRequest(std::bind(&HttpEndpoint::fetchSettings, this, _1), authenticationPredicate)); updateSettings(request, json);
server->addHandler(GEThandler); } else {
request->send(405, "application/json", "{\"message\":\"Method Not Allowed\"}");
// create the POST }
POSThandler = },
new AsyncCallbackJsonWebHandler(servicePath, authenticationPredicate));
securityManager->wrapCallback(std::bind(&HttpEndpoint::updateSettings, this, _1, _2), authenticationPredicate));
POSThandler->setMethod(HTTP_POST);
server->addHandler(POSThandler); server->addHandler(POSThandler);
} }
@@ -59,20 +57,25 @@ class HttpEndpoint {
request->send(400); request->send(400);
return; return;
} }
JsonObject jsonObject = json.as<JsonObject>(); JsonObject jsonObject = json.as<JsonObject>();
StateUpdateResult outcome = _statefulService->updateWithoutPropagation(jsonObject, _stateUpdater); StateUpdateResult outcome = _statefulService->updateWithoutPropagation(jsonObject, _stateUpdater);
if (outcome == StateUpdateResult::ERROR) { if (outcome == StateUpdateResult::ERROR) {
request->send(400); request->send(400);
return; return;
} else if ((outcome == StateUpdateResult::CHANGED) || (outcome == StateUpdateResult::CHANGED_RESTART)) { } else if ((outcome == StateUpdateResult::CHANGED) || (outcome == StateUpdateResult::CHANGED_RESTART)) {
request->onDisconnect([this]() { _statefulService->callUpdateHandlers(HTTP_ENDPOINT_ORIGIN_ID); }); request->onDisconnect([this]() { _statefulService->callUpdateHandlers(HTTP_ENDPOINT_ORIGIN_ID); });
} }
AsyncJsonResponse * response = new AsyncJsonResponse(false); AsyncJsonResponse * response = new AsyncJsonResponse(false);
jsonObject = response->getRoot().to<JsonObject>(); jsonObject = response->getRoot().to<JsonObject>();
_statefulService->read(jsonObject, _stateReader); _statefulService->read(jsonObject, _stateReader);
if (outcome == StateUpdateResult::CHANGED_RESTART) { if (outcome == StateUpdateResult::CHANGED_RESTART) {
response->setCode(205); // reboot required response->setCode(205); // reboot required
} }
response->setLength(); response->setLength();
request->send(response); request->send(response);
} }

View File

@@ -71,7 +71,7 @@ build_flags =
-D EMSESP_TEST -D EMSESP_TEST
-D EMSESP_DEBUG -D EMSESP_DEBUG
-D CONFIG_ETH_ENABLED -D CONFIG_ETH_ENABLED
-D TASMOTA_SDK -D CONFIG_ASYNC_TCP_STACK_SIZE=8192
'-DEMSESP_DEFAULT_BOARD_PROFILE="Test"' '-DEMSESP_DEFAULT_BOARD_PROFILE="Test"'
[env:lolin_s3] [env:lolin_s3]