Webserver addition and TactilityC symbols (#451)
This commit is contained in:
@@ -9,39 +9,58 @@ namespace tt::network {
|
||||
|
||||
static const auto LOGGER = Logger("HttpServer");
|
||||
|
||||
static constexpr size_t INTERNAL_URI_HANDLER_COUNT = 2;
|
||||
|
||||
bool HttpServer::startInternal() {
|
||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||
config.stack_size = stackSize;
|
||||
config.server_port = port;
|
||||
config.uri_match_fn = matchUri;
|
||||
config.max_uri_handlers = handlers.size() + INTERNAL_URI_HANDLER_COUNT;
|
||||
|
||||
if (httpd_start(&server, &config) != ESP_OK) {
|
||||
LOGGER.error("Failed to start http server on port {}", port);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool allRegistered = true;
|
||||
for (std::vector<httpd_uri_t>::reference handler : handlers) {
|
||||
httpd_register_uri_handler(server, &handler);
|
||||
if (httpd_register_uri_handler(server, &handler) != ESP_OK) {
|
||||
LOGGER.error("Failed to register URI handler: {}", handler.uri);
|
||||
allRegistered = false;
|
||||
}
|
||||
}
|
||||
if (!allRegistered) {
|
||||
httpd_stop(server);
|
||||
server = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGGER.info("Started on port {}", config.server_port);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HttpServer::stopInternal() {
|
||||
LOGGER.info("Stopping server");
|
||||
if (server != nullptr && httpd_stop(server) != ESP_OK) {
|
||||
LOGGER.warn("Error while stopping");
|
||||
server = nullptr;
|
||||
if (server != nullptr) {
|
||||
if (httpd_stop(server) == ESP_OK) {
|
||||
server = nullptr;
|
||||
} else {
|
||||
LOGGER.warn("Error while stopping");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HttpServer::start() {
|
||||
bool HttpServer::start() {
|
||||
auto lock = mutex.asScopedLock();
|
||||
lock.lock();
|
||||
|
||||
startInternal();
|
||||
if (isStarted()) {
|
||||
LOGGER.warn("Already started");
|
||||
return true;
|
||||
}
|
||||
|
||||
return startInternal();
|
||||
}
|
||||
|
||||
void HttpServer::stop() {
|
||||
@@ -50,6 +69,7 @@ void HttpServer::stop() {
|
||||
|
||||
if (!isStarted()) {
|
||||
LOGGER.warn("Not started");
|
||||
return;
|
||||
}
|
||||
|
||||
stopInternal();
|
||||
|
||||
@@ -83,18 +83,35 @@ std::unique_ptr<char[]> receiveByteArray(httpd_req_t* request, size_t length, si
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
constexpr int MAX_TIMEOUT_RETRIES = 5;
|
||||
int timeout_retries = 0;
|
||||
while (bytesRead < length) {
|
||||
size_t read_size = length - bytesRead;
|
||||
size_t bytes_received = httpd_req_recv(request, buffer + bytesRead, read_size);
|
||||
int bytes_received = httpd_req_recv(request, buffer + bytesRead, read_size);
|
||||
if (bytes_received == HTTPD_SOCK_ERR_TIMEOUT) {
|
||||
// Timeout - retry with backoff
|
||||
timeout_retries++;
|
||||
if (timeout_retries >= MAX_TIMEOUT_RETRIES) {
|
||||
LOGGER.warn("Recv timeout after {} retries, read {}/{} bytes", timeout_retries, bytesRead, length);
|
||||
free(buffer);
|
||||
return nullptr;
|
||||
}
|
||||
LOGGER.warn("Recv timeout, retry {}/{}", timeout_retries, MAX_TIMEOUT_RETRIES);
|
||||
vTaskDelay(pdMS_TO_TICKS(100 * timeout_retries)); // Exponential backoff
|
||||
continue;
|
||||
}
|
||||
if (bytes_received <= 0) {
|
||||
LOGGER.warn("Received error {} after reading {}/{} bytes", bytes_received, bytesRead, length);
|
||||
free(buffer);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Successful read - reset timeout counter
|
||||
timeout_retries = 0;
|
||||
bytesRead += bytes_received;
|
||||
}
|
||||
|
||||
return std::unique_ptr<char[]>(std::move(buffer));
|
||||
return std::unique_ptr<char[]>(buffer);
|
||||
}
|
||||
|
||||
std::string receiveTextUntil(httpd_req_t* request, const std::string& terminator) {
|
||||
@@ -131,7 +148,7 @@ std::map<std::string, std::string> parseContentDisposition(const std::vector<std
|
||||
|
||||
auto parseable = content_disposition_header->substr(prefix.size());
|
||||
auto parts = string::split(parseable, "; ");
|
||||
for (auto part : parts) {
|
||||
for (const auto& part : parts) {
|
||||
auto key_value = string::split(part, "=");
|
||||
if (key_value.size() == 2) {
|
||||
// Trim trailing newlines
|
||||
@@ -150,7 +167,7 @@ std::map<std::string, std::string> parseContentDisposition(const std::vector<std
|
||||
bool readAndDiscardOrSendError(httpd_req_t* request, const std::string& toRead) {
|
||||
size_t bytes_read;
|
||||
auto buffer = receiveByteArray(request, toRead.length(), bytes_read);
|
||||
if (bytes_read != toRead.length()) {
|
||||
if (buffer == nullptr || bytes_read != toRead.length()) {
|
||||
httpd_resp_send_err(request, HTTPD_400_BAD_REQUEST, "failed to read discardable data");
|
||||
return false;
|
||||
}
|
||||
@@ -184,7 +201,7 @@ size_t receiveFile(httpd_req_t* request, size_t length, const std::string& fileP
|
||||
LOGGER.error("Receive failed");
|
||||
break;
|
||||
}
|
||||
if (fwrite(buffer, 1, receive_chunk_size, file) != receive_chunk_size) {
|
||||
if (fwrite(buffer, 1, receive_chunk_size, file) != (size_t)receive_chunk_size) {
|
||||
LOGGER.error("Failed to write all bytes");
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user