mirror of
https://github.com/rstrouse/ESPSomfy-RTS.git
synced 2026-10-31 13:52:15 +01:00
Every append found the end of the buffer with strlen(), up to four times per append and four appends per field, so building a response cost the square of its size. /discovery fills a 4 KB buffer and spent about 195 ms of its ~210 ms there (shades 126 ms, groups 69 ms), all on the async_tcp task that serves every socket and web request. Keep the length in the formatter and write every append at the end through one helper. The web response and socket event subclasses and ControllerChunker use the tracked length too. Output is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
102 lines
3.3 KiB
C++
102 lines
3.3 KiB
C++
#include "WResp.h"
|
|
#include "esp_log.h"
|
|
#include "Timing.h"
|
|
|
|
static const char *TAG = "WResp";
|
|
#define EMIT_SLOW_MS 20
|
|
void JsonSockEvent::beginEvent(AsyncWebSocket *server, const char *evt, char *buff, size_t buffSize) {
|
|
this->server = server;
|
|
this->_evt = evt;
|
|
this->buff = buff;
|
|
this->buffSize = buffSize;
|
|
this->_nocomma = true;
|
|
this->_closed = false;
|
|
this->_overflow = false;
|
|
const int n = snprintf(this->buff, buffSize, "42[%s,", evt);
|
|
this->_len = n < 0 ? 0 : ((size_t)n < buffSize ? (size_t)n : buffSize - 1);
|
|
}
|
|
void JsonSockEvent::closeEvent() {
|
|
if(!this->_closed) {
|
|
// The ] and the terminator both have to fit.
|
|
if(this->_len + 1 < buffSize) this->_appendAt("]", false, 1);
|
|
else this->_overflow = true;
|
|
}
|
|
this->_nocomma = true;
|
|
this->_closed = true;
|
|
}
|
|
void JsonSockEvent::endEvent(uint32_t clientId) {
|
|
this->closeEvent();
|
|
// Part of it is missing so clients would only fail to parse it.
|
|
if(this->_overflow) {
|
|
ESP_LOGE(TAG, "Socket event too large for %u bytes, not sent: %.32s", (unsigned)this->buffSize, this->buff);
|
|
return;
|
|
}
|
|
ElapsedTimer timer;
|
|
if(clientId == 0) this->server->textAll(this->buff);
|
|
else this->server->text(clientId, this->buff);
|
|
// Sends happen every few seconds, so only the slow ones are worth a line.
|
|
const uint32_t us = timer.us();
|
|
if(us < EMIT_SLOW_MS * 1000) return;
|
|
char what[80];
|
|
if(clientId == 0) snprintf(what, sizeof(what), "Socket emit %s (%u bytes) to all", this->_evt, (unsigned)this->_len);
|
|
else snprintf(what, sizeof(what), "Socket emit %s (%u bytes) to %lu", this->_evt, (unsigned)this->_len, (unsigned long)clientId);
|
|
logElapsed(TAG, what, us);
|
|
}
|
|
void JsonSockEvent::_safecat(const char *val, bool escape) {
|
|
const size_t vlen = escape ? this->calcEscapedLength(val) + 2 : strlen(val);
|
|
if(this->_len + vlen >= this->buffSize) {
|
|
this->_overflow = true;
|
|
return;
|
|
}
|
|
this->_appendAt(val, escape, vlen);
|
|
}
|
|
void AsyncJsonResp::beginResponse(AsyncWebServerRequest *request, char *buff, size_t buffSize) {
|
|
this->_request = request;
|
|
this->buff = buff;
|
|
this->buffSize = buffSize;
|
|
this->buff[0] = 0x00;
|
|
this->_len = 0;
|
|
this->_nocomma = true;
|
|
this->_headersSent = false;
|
|
this->_overflow = false;
|
|
this->_stream = request->beginResponseStream("application/json");
|
|
}
|
|
void AsyncJsonResp::endResponse() {
|
|
if(this->_len) this->flush();
|
|
if(this->_request && this->_stream) {
|
|
this->_request->send(this->_stream);
|
|
}
|
|
}
|
|
void AsyncJsonResp::flush() {
|
|
if(this->_stream && this->_len > 0) {
|
|
this->_stream->write((const uint8_t *)this->buff, this->_len);
|
|
this->buff[0] = 0x00;
|
|
this->_len = 0;
|
|
}
|
|
}
|
|
void AsyncJsonResp::_safecat(const char *val, bool escape) {
|
|
const size_t vlen = escape ? this->calcEscapedLength(val) + 2 : strlen(val);
|
|
if(vlen + this->_len >= this->buffSize) {
|
|
this->flush();
|
|
if(vlen + this->_len >= this->buffSize) {
|
|
// Bigger than the whole buffer so stream it straight out.
|
|
if(!this->_stream) {
|
|
this->_overflow = true;
|
|
return;
|
|
}
|
|
if(!escape) {
|
|
this->_stream->print(val);
|
|
return;
|
|
}
|
|
char esc[7];
|
|
this->_stream->print("\"");
|
|
for(size_t i = 0; val[i]; i++) {
|
|
escapeChar(val[i], esc);
|
|
this->_stream->print(esc);
|
|
}
|
|
this->_stream->print("\"");
|
|
return;
|
|
}
|
|
}
|
|
this->_appendAt(val, escape, vlen);
|
|
}
|