fix: oom exceptions for OPDS, KOSync, and OTA via wolfssl (#2475)

This commit is contained in:
Justin Mitchell
2026-07-12 01:53:26 +03:00
committed by GitHub
parent 1f5669a08a
commit 3e627112f6
13 changed files with 413 additions and 233 deletions
@@ -1,5 +1,6 @@
#include "OpdsBookBrowserActivity.h"
#include <Arduino.h>
#include <GfxRenderer.h>
#include <I18n.h>
#include <Logging.h>
@@ -19,7 +20,9 @@
namespace {
constexpr int PAGE_ITEMS = 23;
}
constexpr int DOWNLOAD_PROGRESS_STEP_PERCENT = 5;
constexpr unsigned long DOWNLOAD_PROGRESS_MIN_UPDATE_MS = 5000;
} // namespace
void OpdsBookBrowserActivity::onEnter() {
Activity::onEnter();
@@ -193,7 +196,7 @@ void OpdsBookBrowserActivity::fetchFeed(const std::string& path) {
return;
}
std::string url = (path.find("http") == 0) ? path : UrlUtils::buildUrl(server.url, path);
std::string url = UrlUtils::buildUrl(server.url, path);
LOG_DBG("OPDS", "Fetching: %s", url.c_str());
OpdsParser parser;
{
@@ -216,14 +219,19 @@ void OpdsBookBrowserActivity::fetchFeed(const std::string& path) {
searchTemplate = parser.getSearchTemplate();
const auto& nextUrl = parser.getNextPageUrl();
const auto& prevUrl = parser.getPrevPageUrl();
const bool feedTruncated = parser.truncated();
entries = std::move(parser).getEntries();
entries.reserve(entries.size() + (prevUrl.empty() ? 0 : 1) + (nextUrl.empty() ? 0 : 1));
if (!prevUrl.empty()) {
entries.insert(entries.begin(), OpdsEntry{OpdsEntryType::NAVIGATION, tr(STR_PREV_PAGE), "", prevUrl, ""});
}
if (!nextUrl.empty()) {
entries.push_back(OpdsEntry{OpdsEntryType::NAVIGATION, tr(STR_NEXT_PAGE), "", nextUrl, ""});
}
if (feedTruncated) {
LOG_INF("OPDS", "Feed truncated to fit memory");
}
selectorIndex = 0;
state = entries.empty() ? BrowserState::ERROR : BrowserState::BROWSING;
@@ -231,6 +239,8 @@ void OpdsBookBrowserActivity::fetchFeed(const std::string& path) {
requestUpdate();
}
void OpdsBookBrowserActivity::releaseEntries() { std::vector<OpdsEntry>().swap(entries); }
void OpdsBookBrowserActivity::navigateToEntry(const OpdsEntry& entry) {
navigationHistory.push_back(currentPath);
// Resolve to a full URL so sub-sub-navigation retains parent path context
@@ -239,7 +249,7 @@ void OpdsBookBrowserActivity::navigateToEntry(const OpdsEntry& entry) {
state = BrowserState::LOADING;
statusMessage = tr(STR_LOADING);
entries.clear();
releaseEntries();
selectorIndex = 0;
requestUpdate(true);
fetchFeed(currentPath);
@@ -253,7 +263,7 @@ void OpdsBookBrowserActivity::navigateBack() {
navigationHistory.pop_back();
state = BrowserState::LOADING;
statusMessage = tr(STR_LOADING);
entries.clear();
releaseEntries();
selectorIndex = 0;
requestUpdate();
fetchFeed(currentPath);
@@ -273,12 +283,22 @@ void OpdsBookBrowserActivity::downloadBook(const OpdsEntry& book) {
"/" + StringUtils::sanitizeFilename((book.author.empty() ? "" : book.author + " - ") + book.title) + ".epub";
LOG_DBG("OPDS", "Downloading: %s -> %s", downloadUrl.c_str(), filename.c_str());
int lastRenderedPercent = -1;
unsigned long lastProgressUpdateMs = 0;
const auto result = HttpDownloader::downloadToFile(
downloadUrl, filename,
[this](const size_t downloaded, const size_t total) {
[this, &lastRenderedPercent, &lastProgressUpdateMs](const size_t downloaded, const size_t total) {
downloadProgress = downloaded;
downloadTotal = total;
requestUpdate(true);
const int percent = total > 0 ? static_cast<int>(static_cast<uint64_t>(downloaded) * 100 / total) : 0;
const unsigned long now = millis();
if (percent >= 100 || lastRenderedPercent < 0 ||
percent >= lastRenderedPercent + DOWNLOAD_PROGRESS_STEP_PERCENT ||
now - lastProgressUpdateMs >= DOWNLOAD_PROGRESS_MIN_UPDATE_MS) {
lastRenderedPercent = percent;
lastProgressUpdateMs = now;
requestUpdate(true);
}
},
nullptr, server.username, server.password);
@@ -286,6 +306,7 @@ void OpdsBookBrowserActivity::downloadBook(const OpdsEntry& book) {
clearBookCache(filename);
state = BrowserState::BROWSING;
} else {
LOG_ERR("OPDS", "Download failed: %d", static_cast<int>(result));
state = BrowserState::ERROR;
errorMessage = tr(STR_DOWNLOAD_FAILED);
}
@@ -340,6 +361,8 @@ void OpdsBookBrowserActivity::performSearch(const std::string& query) {
state = BrowserState::LOADING;
statusMessage = tr(STR_LOADING);
releaseEntries();
selectorIndex = 0;
requestUpdate(true);
fetchFeed(url);
}