Add TemplateEngineAsyncWeb for safe ESPAsyncWebServer chunked responses

Chunk callbacks may see maxLen==0 or need another tick before progress; plain
0 ends the body and breaks browsers. Provide helpers that use
RESPONSE_TRY_AGAIN, bounded template render retries, and disconnect cleanup.
Update the README and async examples to use the shared wrapper.
This commit is contained in:
2026-05-06 00:44:54 +10:00
parent 2a1ef2de63
commit 9e998f92a2
4 changed files with 182 additions and 50 deletions
+4 -19
View File
@@ -1,5 +1,6 @@
#include <Arduino.h>
#include <TemplateEngine.h>
#include <TemplateEngineAsyncWeb.h>
#include <cstring>
#include <memory>
#include <DNSServer.h>
@@ -219,25 +220,9 @@ void streamTemplate(AsyncWebServerRequest* request,
ctx->setRegistry(registryPtr.get());
TemplateRenderer::initializeContext(*ctx, rootTemplate);
request->onDisconnect([ctx]() mutable {
ctx.reset();
});
AsyncWebServerResponse* response = request->beginChunkedResponse(
"text/html; charset=utf-8",
[ctx](uint8_t* buffer, size_t maxLen, size_t /*index*/) mutable -> size_t {
if (!ctx) {
return 0;
}
size_t written = TemplateRenderer::renderNextChunk(*ctx, buffer, maxLen);
if (!written || TemplateRenderer::isComplete(*ctx) || TemplateRenderer::hasError(*ctx)) {
ctx.reset();
}
return written;
});
AsyncWebServerResponse* response =
TemplateEngineAsyncWeb::beginSafeTemplateResponse(
request, "text/html; charset=utf-8", ctx, 128);
response->addHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response->addHeader("Pragma", "no-cache");
+4 -17
View File
@@ -1,5 +1,6 @@
#include <Arduino.h>
#include <TemplateEngine.h>
#include <TemplateEngineAsyncWeb.h>
#include <memory>
#include <cstring>
#include <DNSServer.h>
@@ -86,23 +87,9 @@ void streamTemplate(AsyncWebServerRequest* request,
ctx->setRegistry(registryPtr.get());
TemplateRenderer::initializeContext(*ctx, tpl);
request->onDisconnect([ctx]() mutable {
ctx.reset();
});
AsyncWebServerResponse* response = request->beginChunkedResponse(
"text/html; charset=utf-8",
[ctx](uint8_t* buffer, size_t maxLen, size_t) mutable -> size_t {
if (!ctx) {
return 0;
}
size_t written = TemplateRenderer::renderNextChunk(*ctx, buffer, maxLen);
if (!written || TemplateRenderer::isComplete(*ctx) || TemplateRenderer::hasError(*ctx)) {
ctx.reset();
}
return written;
});
AsyncWebServerResponse* response =
TemplateEngineAsyncWeb::beginSafeTemplateResponse(
request, "text/html; charset=utf-8", ctx, 128);
response->addHeader("Cache-Control", "no-cache");
request->send(response);