From abbf69649e1bcb3081409311cc5af770f1539c5c Mon Sep 17 00:00:00 2001 From: jpirnay Date: Tue, 7 Apr 2026 20:24:51 +0200 Subject: [PATCH 1/6] Revert "Merge pull request #25 from jpirnay/fix-pr1582" and refactor koreader --- lib/Epub/Epub/Section.cpp | 2 +- .../Epub/parsers/ChapterHtmlSlimParser.cpp | 118 ++++----- lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h | 1 - lib/GfxRenderer/GfxRenderer.cpp | 5 + lib/KOReaderSync/KOReaderSyncClient.cpp | 215 ++++++++++++--- lib/KOReaderSync/KOReaderSyncClient.h | 14 +- platformio.ini | 2 +- scripts/generate_test_epub.py | 107 +------- src/activities/reader/EpubReaderActivity.cpp | 62 ++++- src/activities/reader/EpubReaderActivity.h | 2 + .../reader/KOReaderSyncActivity.cpp | 247 +++++++++++++++--- src/activities/reader/KOReaderSyncActivity.h | 9 + test/epubs/test_jpeg_images.epub | Bin 306366 -> 322942 bytes test/epubs/test_layout_regressions.epub | Bin 27331 -> 0 bytes test/epubs/test_mixed_images.epub | Bin 52078 -> 52245 bytes test/epubs/test_png_images.epub | Bin 100985 -> 97996 bytes test/epubs/test_text_rendering.epub | Bin 2886 -> 2886 bytes 17 files changed, 516 insertions(+), 268 deletions(-) delete mode 100644 test/epubs/test_layout_regressions.epub diff --git a/lib/Epub/Epub/Section.cpp b/lib/Epub/Epub/Section.cpp index ae9fbf63..499e9437 100644 --- a/lib/Epub/Epub/Section.cpp +++ b/lib/Epub/Epub/Section.cpp @@ -12,7 +12,7 @@ #include "parsers/ChapterHtmlSlimParser.h" namespace { -constexpr uint8_t SECTION_FILE_VERSION = 22; +constexpr uint8_t SECTION_FILE_VERSION = 20; constexpr uint32_t HEADER_SIZE = sizeof(uint8_t) + // SECTION_FILE_VERSION sizeof(int) + // fontId sizeof(float) + // lineCompression diff --git a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp index bd3f3182..a7982a53 100644 --- a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp +++ b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp @@ -122,28 +122,6 @@ bool isZeroHeightSpacerParagraph(const char* name, const std::string& styleAttr) return hasZeroHeight && hasZeroMargin && hasZeroBorder; } -BlockStyle getInheritedBlockStyle(const BlockStyle& parent, const BlockStyle& child) { - BlockStyle inherited = child; - - inherited.marginLeft = static_cast(parent.marginLeft + child.marginLeft); - inherited.marginRight = static_cast(parent.marginRight + child.marginRight); - inherited.paddingLeft = static_cast(parent.paddingLeft + child.paddingLeft); - inherited.paddingRight = static_cast(parent.paddingRight + child.paddingRight); - - if (!child.textIndentDefined) { - inherited.textIndent = parent.textIndent; - inherited.textIndentDefined = parent.textIndentDefined; - } - - if (!child.textAlignDefined) { - inherited.alignment = parent.alignment; - inherited.textAlignDefined = parent.textAlignDefined; - } - - inherited.fromBrElement = false; - return inherited; -} - // Update effective bold/italic/underline based on block style and inline style stack void ChapterHtmlSlimParser::updateEffectiveInlineStyle() { // Start with block-level styles @@ -198,9 +176,11 @@ void ChapterHtmlSlimParser::startNewTextBlock(const BlockStyle& blockStyle) { if (currentTextBlock) { // already have a text block running and it is empty - just reuse it if (currentTextBlock->isEmpty()) { + // Merge with existing block style to accumulate CSS styling from parent block elements. + // This handles cases like

text

where the + // div's margin should be preserved, even though it has no direct text content. BlockStyle incoming = blockStyle; - const BlockStyle& currentStyle = currentTextBlock->getBlockStyle(); - const bool brGapPending = currentStyle.fromBrElement; + const bool brGapPending = currentTextBlock->getBlockStyle().fromBrElement; if (brGapPending) { // The empty block was created by a
section separator. Inject a full line of // blank space before the following paragraph so the scene/section break is visible. @@ -208,8 +188,12 @@ void ChapterHtmlSlimParser::startNewTextBlock(const BlockStyle& blockStyle) { const int16_t lineHeight = static_cast(renderer.getLineHeight(fontId) * lineCompression + 0.5f); incoming.marginTop = static_cast(incoming.marginTop + lineHeight); } - incoming.fromBrElement = blockStyle.fromBrElement; - currentTextBlock->setBlockStyle(incoming); + + BlockStyle merged = currentTextBlock->getBlockStyle().getCombinedBlockStyle(incoming); + // Preserve only whether the current empty block still represents
separators. + // This lets consecutive
accumulate one line each without leaking the flag to real content blocks. + merged.fromBrElement = blockStyle.fromBrElement; + currentTextBlock->setBlockStyle(merged); if (!pendingAnchorId.empty()) { if (std::find(tocAnchors.begin(), tocAnchors.end(), pendingAnchorId) != tocAnchors.end()) { @@ -491,25 +475,19 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* } const bool hasCssHeight = imgStyle.hasImageHeight(); const bool hasCssWidth = imgStyle.hasImageWidth(); - int containerWidth = self->viewportWidth; - if (self->currentTextBlock) { - const int inset = self->currentTextBlock->getBlockStyle().totalHorizontalInset(); - if (inset > 0 && inset < self->viewportWidth) { - containerWidth = self->viewportWidth - inset; - } - } if (hasCssHeight && hasCssWidth && dims.width > 0 && dims.height > 0) { - // Both CSS height and width set: resolve both, then clamp to the current container preserving ratio. + // Both CSS height and width set: resolve both, then clamp to viewport preserving requested ratio displayHeight = static_cast( imgStyle.imageHeight.toPixels(emSize, static_cast(self->viewportHeight)) + 0.5f); - displayWidth = - static_cast(imgStyle.imageWidth.toPixels(emSize, static_cast(containerWidth)) + 0.5f); + displayWidth = static_cast( + imgStyle.imageWidth.toPixels(emSize, static_cast(self->viewportWidth)) + 0.5f); if (displayHeight < 1) displayHeight = 1; if (displayWidth < 1) displayWidth = 1; - if (displayWidth > containerWidth || displayHeight > self->viewportHeight) { - float scaleX = - (displayWidth > containerWidth) ? static_cast(containerWidth) / displayWidth : 1.0f; + if (displayWidth > self->viewportWidth || displayHeight > self->viewportHeight) { + float scaleX = (displayWidth > self->viewportWidth) + ? static_cast(self->viewportWidth) / displayWidth + : 1.0f; float scaleY = (displayHeight > self->viewportHeight) ? static_cast(self->viewportHeight) / displayHeight : 1.0f; @@ -534,8 +512,8 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* static_cast(displayHeight * (static_cast(dims.width) / dims.height) + 0.5f); if (displayWidth < 1) displayWidth = 1; } - if (displayWidth > containerWidth) { - displayWidth = containerWidth; + if (displayWidth > self->viewportWidth) { + displayWidth = self->viewportWidth; // Rescale height to preserve aspect ratio when width is clamped displayHeight = static_cast(displayWidth * (static_cast(dims.height) / dims.width) + 0.5f); @@ -544,10 +522,10 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* if (displayWidth < 1) displayWidth = 1; LOG_DBG("EHP", "Display size from CSS height: %dx%d", displayWidth, displayHeight); } else if (hasCssWidth && !hasCssHeight && dims.width > 0 && dims.height > 0) { - // Use CSS width (resolve % against container width) and derive height from aspect ratio. - displayWidth = - static_cast(imgStyle.imageWidth.toPixels(emSize, static_cast(containerWidth)) + 0.5f); - if (displayWidth > containerWidth) displayWidth = containerWidth; + // Use CSS width (resolve % against viewport width) and derive height from aspect ratio + displayWidth = static_cast( + imgStyle.imageWidth.toPixels(emSize, static_cast(self->viewportWidth)) + 0.5f); + if (displayWidth > self->viewportWidth) displayWidth = self->viewportWidth; if (displayWidth < 1) displayWidth = 1; displayHeight = static_cast(displayWidth * (static_cast(dims.height) / dims.width) + 0.5f); @@ -561,8 +539,8 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* if (displayHeight < 1) displayHeight = 1; LOG_DBG("EHP", "Display size from CSS width: %dx%d", displayWidth, displayHeight); } else { - // Scale to fit the current container while maintaining aspect ratio. - int maxWidth = containerWidth; + // Scale to fit viewport while maintaining aspect ratio + int maxWidth = self->viewportWidth; int maxHeight = self->viewportHeight; float scaleX = (dims.width > maxWidth) ? (float)maxWidth / dims.width : 1.0f; float scaleY = (dims.height > maxHeight) ? (float)maxHeight / dims.height : 1.0f; @@ -676,10 +654,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* // Fallback to alt text if image processing fails if (!alt.empty()) { alt = "[Image: " + alt + "]"; - const BlockStyle altBlockStyle = self->blockStyleStack.empty() - ? centeredBlockStyle - : getInheritedBlockStyle(self->blockStyleStack.back(), centeredBlockStyle); - self->startNewTextBlock(altBlockStyle); + self->startNewTextBlock(centeredBlockStyle); self->italicUntilDepth = std::min(self->italicUntilDepth, self->depth); self->depth += 1; self->characterData(userData, alt.c_str(), alt.length()); @@ -793,9 +768,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* if (self->embeddedStyle && cssStyle.hasTextAlign()) { headerBlockStyle.alignment = cssStyle.textAlign; } - const BlockStyle inheritedHeaderBlockStyle = getInheritedBlockStyle(self->blockStyleStack.back(), headerBlockStyle); - self->blockStyleStack.push_back(inheritedHeaderBlockStyle); - self->startNewTextBlock(inheritedHeaderBlockStyle); + self->startNewTextBlock(headerBlockStyle); self->boldUntilDepth = std::min(self->boldUntilDepth, self->depth); self->updateEffectiveInlineStyle(); } else if (matches(name, BLOCK_TAGS, NUM_BLOCK_TAGS)) { @@ -807,9 +780,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* blockStyle.alignment = cssStyle.textAlign; blockStyle.textAlignDefined = true; } - const BlockStyle inheritedBlockStyle = getInheritedBlockStyle(self->blockStyleStack.back(), blockStyle); - self->blockStyleStack.push_back(inheritedBlockStyle); - self->startNewTextBlock(inheritedBlockStyle); + self->startNewTextBlock(blockStyle); self->updateEffectiveInlineStyle(); self->skipTextUntilDepth = self->depth; @@ -843,9 +814,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* blockStyle.alignment = cssStyle.textAlign; blockStyle.textAlignDefined = true; } - const BlockStyle inheritedBlockStyle = getInheritedBlockStyle(self->blockStyleStack.back(), blockStyle); - self->blockStyleStack.push_back(inheritedBlockStyle); - self->startNewTextBlock(inheritedBlockStyle); + self->startNewTextBlock(blockStyle); self->updateEffectiveInlineStyle(); if (strcmp(name, "li") == 0) { @@ -1289,24 +1258,29 @@ void XMLCALL ChapterHtmlSlimParser::endElement(void* userData, const XML_Char* n self->currentCssStyle.reset(); self->updateEffectiveInlineStyle(); - if (strcmp(name, "br") != 0 && self->blockStyleStack.size() > 1) { - self->blockStyleStack.pop_back(); - if (self->currentTextBlock && self->currentTextBlock->isEmpty()) { - self->currentTextBlock->setBlockStyle(self->blockStyleStack.back()); + // Reset alignment on empty text blocks to prevent stale alignment from bleeding + // into the next sibling element. This fixes issue #1026 where an empty

(default + // Center) followed by an image-only

causes Center to persist through the chain + // of empty block reuse into subsequent text paragraphs. + // Margins/padding are preserved so parent element spacing still accumulates correctly. + if (self->currentTextBlock && self->currentTextBlock->isEmpty()) { + auto style = self->currentTextBlock->getBlockStyle(); + // Keep alignment only when closing the
separator itself so subsequent text + // within the same block container stays aligned. Reset alignment when closing + // other block tags (e.g. div/p) to avoid leaking centered/right alignment globally. + const bool preserveForBrClose = style.fromBrElement && strcmp(name, "br") == 0; + if (!preserveForBrClose) { + style.textAlignDefined = false; + style.alignment = (self->paragraphAlignment == static_cast(CssTextAlign::None)) + ? CssTextAlign::Justify + : static_cast(self->paragraphAlignment); + self->currentTextBlock->setBlockStyle(style); } } } } bool ChapterHtmlSlimParser::parseAndBuildPages() { - BlockStyle rootBlockStyle; - rootBlockStyle.alignment = (this->paragraphAlignment == static_cast(CssTextAlign::None)) - ? CssTextAlign::Justify - : static_cast(this->paragraphAlignment); - blockStyleStack.clear(); - blockStyleStack.reserve(8); - blockStyleStack.push_back(rootBlockStyle); - auto paragraphAlignmentBlockStyle = BlockStyle(); paragraphAlignmentBlockStyle.textAlignDefined = true; // Resolve None sentinel to Justify for initial block (no CSS context yet) diff --git a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h index f63b7fb3..ecda8da1 100644 --- a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h +++ b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h @@ -65,7 +65,6 @@ class ChapterHtmlSlimParser { bool hasUnderline = false, underline = false; }; std::vector inlineStyleStack; - std::vector blockStyleStack; CssStyle currentCssStyle; bool effectiveBold = false; bool effectiveItalic = false; diff --git a/lib/GfxRenderer/GfxRenderer.cpp b/lib/GfxRenderer/GfxRenderer.cpp index 97f0e696..bce22e08 100644 --- a/lib/GfxRenderer/GfxRenderer.cpp +++ b/lib/GfxRenderer/GfxRenderer.cpp @@ -1917,7 +1917,12 @@ void GfxRenderer::restoreBwBuffer() { } if (missingChunks) { + // Store failed part-way (or was skipped), so we cannot restore BW bytes safely. + // Still cleanup grayscale staging buffers to avoid retaining large temporary + // allocations that can later starve TLS handshakes. + display.cleanupGrayscaleBuffers(frameBuffer); freeBwBufferChunks(); + LOG_ERR("GFX", "BW restore skipped due to missing chunks; cleaned grayscale buffers only"); return; } diff --git a/lib/KOReaderSync/KOReaderSyncClient.cpp b/lib/KOReaderSync/KOReaderSyncClient.cpp index ac5136cf..d98a0d89 100644 --- a/lib/KOReaderSync/KOReaderSyncClient.cpp +++ b/lib/KOReaderSync/KOReaderSyncClient.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -10,6 +11,7 @@ #include #include +#include #include #include @@ -22,6 +24,9 @@ unsigned KOReaderSyncClient::lastContigHeapAtFailure = 0; const char* KOReaderSyncClient::lastOperation = ""; namespace { +bool g_keepSessionOpen = false; +esp_http_client_handle_t g_sessionClient = nullptr; + // Static buffer for the detail string returned by lastFailureDetail() — sized to fit // the longest expected message including esp_err name (~32 chars), opcode (~10), heap // numbers, and HTTP status. Single-threaded sync flow makes static safe. @@ -41,10 +46,20 @@ void beginRequest(const char* operation) { constexpr char DEVICE_NAME[] = "CrossPoint"; constexpr char DEVICE_ID[] = "crosspoint-reader"; -// Small TLS buffers to fit in ESP32-C3's limited heap (~46KB free after WiFi). -// KOSync payloads are tiny JSON (<1KB), so 2KB buffers are sufficient. -// Default 16KB buffers cause OOM during TLS handshake. -constexpr int HTTP_BUF_SIZE = 2048; +// Use small HTTP/TLS buffers to reduce peak handshake memory on ESP32-C3. +// Payloads are tiny JSON, so throughput impact is minimal while avoiding +// large transient allocations from default client buffer sizes. +constexpr int HTTP_BUF_SIZE = 1024; +constexpr unsigned TLS_CONTIG_HEAP_TOLERANCE = 512; + +// Captures radio/link state around failed connects. +// Why: many field failures look like TLS errors but are actually weak WiFi. +void logWifiSnapshot(const char* stage) { + const wl_status_t status = WiFi.status(); + const int32_t rssi = WiFi.RSSI(); + LOG_DBG("KOSync", "%s: wifi_status=%d rssi=%ld ip=%s", stage, static_cast(status), static_cast(rssi), + WiFi.localIP().toString().c_str()); +} // Response buffer for reading HTTP body struct ResponseBuffer { @@ -64,6 +79,20 @@ struct ResponseBuffer { } }; +ResponseBuffer g_sessionResponseBuf; + +void clearResponseBuffer(ResponseBuffer* buf) { + if (!buf) return; + if (buf->data) { + buf->len = 0; + buf->data[0] = '\0'; + } +} + +ResponseBuffer* effectiveResponseBuffer(ResponseBuffer* localBuf) { + return g_keepSessionOpen ? &g_sessionResponseBuf : localBuf; +} + // HTTP event handler to collect response body esp_err_t httpEventHandler(esp_http_client_event_t* evt) { auto* buf = static_cast(evt->user_data); @@ -105,10 +134,23 @@ std::string base64Encode(const std::string& input) { // we should proceed; false means caller must abort with NETWORK_ERROR — in which case // lastFailureDetail() will report the heap shortage instead of attempting a doomed handshake. bool checkHeapForTls() { + const bool hasReusableSession = g_keepSessionOpen && g_sessionClient != nullptr; + const bool isUpload = (KOReaderSyncClient::lastOperation && + strcmp(KOReaderSyncClient::lastOperation, "update progress") == 0); + const unsigned requiredContig = + isUpload ? KOReaderSyncClient::MIN_CONTIG_HEAP_FOR_TLS_UPLOAD : KOReaderSyncClient::MIN_CONTIG_HEAP_FOR_TLS; + + // Upload can often reuse the already-established GET connection. In that case + // a full handshake allocation is typically unnecessary, so avoid failing fast + // on contiguous-heap threshold and let the HTTP client attempt reuse. + if (isUpload && hasReusableSession) { + return true; + } + // beginRequest() already populated lastContigHeapAtFailure for the diagnostic path. - if (KOReaderSyncClient::lastContigHeapAtFailure < KOReaderSyncClient::MIN_CONTIG_HEAP_FOR_TLS) { + if (KOReaderSyncClient::lastContigHeapAtFailure + TLS_CONTIG_HEAP_TOLERANCE < requiredContig) { LOG_ERR("KOSync", "Insufficient contiguous heap for TLS: %u available, %u required", - KOReaderSyncClient::lastContigHeapAtFailure, KOReaderSyncClient::MIN_CONTIG_HEAP_FOR_TLS); + KOReaderSyncClient::lastContigHeapAtFailure, requiredContig); // Synthesize an esp_err_t-shaped value so the diagnostic detail string is uniform. KOReaderSyncClient::lastEspError = ESP_ERR_NO_MEM; return false; @@ -119,15 +161,33 @@ bool checkHeapForTls() { // Create configured esp_http_client with small TLS buffers esp_http_client_handle_t createClient(const char* url, ResponseBuffer* buf, esp_http_client_method_t method = HTTP_METHOD_GET) { + ResponseBuffer* activeBuf = effectiveResponseBuffer(buf); + + if (g_keepSessionOpen && g_sessionClient) { + esp_http_client_set_url(g_sessionClient, url); + esp_http_client_set_method(g_sessionClient, method); + + // KOSync auth headers + esp_http_client_set_header(g_sessionClient, "Accept", "application/vnd.koreader.v1+json"); + esp_http_client_set_header(g_sessionClient, "x-auth-user", KOREADER_STORE.getUsername().c_str()); + esp_http_client_set_header(g_sessionClient, "x-auth-key", KOREADER_STORE.getMd5Password().c_str()); + + std::string credentials = KOREADER_STORE.getUsername() + ":" + KOREADER_STORE.getPassword(); + std::string authHeader = "Basic " + base64Encode(credentials); + esp_http_client_set_header(g_sessionClient, "Authorization", authHeader.c_str()); + return g_sessionClient; + } + esp_http_client_config_t config = {}; config.url = url; config.event_handler = httpEventHandler; - config.user_data = buf; + config.user_data = activeBuf; config.method = method; config.timeout_ms = 15000; config.buffer_size = HTTP_BUF_SIZE; config.buffer_size_tx = HTTP_BUF_SIZE; config.crt_bundle_attach = esp_crt_bundle_attach; + config.keep_alive_enable = g_keepSessionOpen; esp_http_client_handle_t client = esp_http_client_init(&config); if (!client) return nullptr; @@ -142,10 +202,28 @@ esp_http_client_handle_t createClient(const char* url, ResponseBuffer* buf, std::string authHeader = "Basic " + base64Encode(credentials); esp_http_client_set_header(client, "Authorization", authHeader.c_str()); + if (g_keepSessionOpen) { + g_sessionClient = client; + } + return client; } } // namespace +void KOReaderSyncClient::beginPersistentSession() { + g_keepSessionOpen = true; + clearResponseBuffer(&g_sessionResponseBuf); +} + +void KOReaderSyncClient::endPersistentSession() { + g_keepSessionOpen = false; + if (g_sessionClient) { + esp_http_client_cleanup(g_sessionClient); + g_sessionClient = nullptr; + } + clearResponseBuffer(&g_sessionResponseBuf); +} + KOReaderSyncClient::Error KOReaderSyncClient::registerUser() { if (!KOREADER_STORE.hasCredentials()) { LOG_DBG("KOSync", "No credentials configured"); @@ -168,6 +246,8 @@ KOReaderSyncClient::Error KOReaderSyncClient::registerUser() { LOG_DBG("KOSync", "Register request body: "); ResponseBuffer buf; + ResponseBuffer* activeBuf = effectiveResponseBuffer(&buf); + clearResponseBuffer(activeBuf); esp_http_client_handle_t client = createClient(url.c_str(), &buf, HTTP_METHOD_POST); if (!client) { lastEspError = ESP_ERR_NO_MEM; @@ -181,10 +261,12 @@ KOReaderSyncClient::Error KOReaderSyncClient::registerUser() { const int httpCode = esp_http_client_get_status_code(client); lastHttpCode = httpCode; lastEspError = err; - esp_http_client_cleanup(client); + if (!g_keepSessionOpen) { + esp_http_client_cleanup(client); + } LOG_DBG("KOSync", "Register response: %d (err: %s) | body: %s", httpCode, esp_err_to_name(err), - buf.data ? buf.data : ""); + activeBuf->data ? activeBuf->data : ""); if (err != ESP_OK) { return NETWORK_ERROR; @@ -198,7 +280,7 @@ KOReaderSyncClient::Error KOReaderSyncClient::registerUser() { } else if (httpCode == 402) { // Both "user already exists" (error 2002) and "registration disabled" (error 2005) // return HTTP 402 on the original kosync server. Distinguish them by body text. - std::string lowerBody = buf.data ? buf.data : ""; + std::string lowerBody = activeBuf->data ? activeBuf->data : ""; std::transform(lowerBody.begin(), lowerBody.end(), lowerBody.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); if (lowerBody.find("already") != std::string::npos) { @@ -226,6 +308,8 @@ KOReaderSyncClient::Error KOReaderSyncClient::authenticate() { lastContigHeapAtFailure); ResponseBuffer buf; + ResponseBuffer* activeBuf = effectiveResponseBuffer(&buf); + clearResponseBuffer(activeBuf); esp_http_client_handle_t client = createClient(url.c_str(), &buf); if (!client) { lastEspError = ESP_ERR_NO_MEM; @@ -236,7 +320,9 @@ KOReaderSyncClient::Error KOReaderSyncClient::authenticate() { const int httpCode = esp_http_client_get_status_code(client); lastHttpCode = httpCode; lastEspError = err; - esp_http_client_cleanup(client); + if (!g_keepSessionOpen) { + esp_http_client_cleanup(client); + } LOG_DBG("KOSync", "Auth response: %d (err: %s)", httpCode, esp_err_to_name(err)); @@ -261,25 +347,47 @@ KOReaderSyncClient::Error KOReaderSyncClient::getProgress(const std::string& doc lastContigHeapAtFailure); ResponseBuffer buf; - esp_http_client_handle_t client = createClient(url.c_str(), &buf); - if (!client) { - lastEspError = ESP_ERR_NO_MEM; - return NETWORK_ERROR; + ResponseBuffer* activeBuf = effectiveResponseBuffer(&buf); + esp_err_t err = ESP_FAIL; + int httpCode = 0; + + for (int attempt = 1; attempt <= 2; attempt++) { + clearResponseBuffer(activeBuf); + + esp_http_client_handle_t client = createClient(url.c_str(), &buf); + if (!client) { + lastEspError = ESP_ERR_NO_MEM; + return NETWORK_ERROR; + } + + logWifiSnapshot("WiFi before getProgress"); + err = esp_http_client_perform(client); + httpCode = esp_http_client_get_status_code(client); + lastHttpCode = httpCode; + lastEspError = err; + if (!g_keepSessionOpen) { + esp_http_client_cleanup(client); + } + + LOG_DBG("KOSync", "Get progress response: %d (err: %s) [attempt %d]", httpCode, esp_err_to_name(err), attempt); + + // Retry exactly once for connect-level failures only. + // Why: this recovers short AP/roaming hiccups without masking persistent + // TLS/auth/server errors that should be surfaced immediately. + if (err == ESP_OK || err != ESP_ERR_HTTP_CONNECT || attempt == 2) { + break; + } + + LOG_ERR("KOSync", "getProgress connect failed on attempt %d, retrying once", attempt); + logWifiSnapshot("WiFi before getProgress retry"); + delay(400); } - esp_err_t err = esp_http_client_perform(client); - const int httpCode = esp_http_client_get_status_code(client); - lastHttpCode = httpCode; - lastEspError = err; - esp_http_client_cleanup(client); - - LOG_DBG("KOSync", "Get progress response: %d (err: %s)", httpCode, esp_err_to_name(err)); - if (err != ESP_OK) return NETWORK_ERROR; - if (httpCode == 200 && buf.data) { + if (httpCode == 200 && activeBuf->data) { JsonDocument doc; - const DeserializationError error = deserializeJson(doc, buf.data); + const DeserializationError error = deserializeJson(doc, activeBuf->data); if (error) { LOG_ERR("KOSync", "JSON parse failed: %s", error.c_str()); @@ -329,23 +437,45 @@ KOReaderSyncClient::Error KOReaderSyncClient::updateProgress(const KOReaderProgr LOG_DBG("KOSync", "Request body: %s", body.c_str()); ResponseBuffer buf; - esp_http_client_handle_t client = createClient(url.c_str(), &buf, HTTP_METHOD_PUT); - if (!client) { - lastEspError = ESP_ERR_NO_MEM; - return NETWORK_ERROR; + ResponseBuffer* activeBuf = effectiveResponseBuffer(&buf); + esp_err_t err = ESP_FAIL; + int httpCode = 0; + + for (int attempt = 1; attempt <= 2; attempt++) { + clearResponseBuffer(activeBuf); + + esp_http_client_handle_t client = createClient(url.c_str(), &buf, HTTP_METHOD_PUT); + if (!client) { + lastEspError = ESP_ERR_NO_MEM; + return NETWORK_ERROR; + } + + esp_http_client_set_header(client, "Content-Type", "application/json"); + esp_http_client_set_post_field(client, body.c_str(), body.length()); + + logWifiSnapshot("WiFi before updateProgress"); + err = esp_http_client_perform(client); + httpCode = esp_http_client_get_status_code(client); + lastHttpCode = httpCode; + lastEspError = err; + if (!g_keepSessionOpen) { + esp_http_client_cleanup(client); + } + + LOG_DBG("KOSync", "Update progress response: %d (err: %s) [attempt %d]", httpCode, esp_err_to_name(err), + attempt); + + // Retry exactly once for connect-level failures only. + // Why: same policy as GET keeps behavior predictable across both endpoints. + if (err == ESP_OK || err != ESP_ERR_HTTP_CONNECT || attempt == 2) { + break; + } + + LOG_ERR("KOSync", "updateProgress connect failed on attempt %d, retrying once", attempt); + logWifiSnapshot("WiFi before updateProgress retry"); + delay(400); } - esp_http_client_set_header(client, "Content-Type", "application/json"); - esp_http_client_set_post_field(client, body.c_str(), body.length()); - - esp_err_t err = esp_http_client_perform(client); - const int httpCode = esp_http_client_get_status_code(client); - lastHttpCode = httpCode; - lastEspError = err; - esp_http_client_cleanup(client); - - LOG_DBG("KOSync", "Update progress response: %d (err: %s)", httpCode, esp_err_to_name(err)); - if (err != ESP_OK) return NETWORK_ERROR; if (httpCode == 200 || httpCode == 202) return OK; if (httpCode == 401) return AUTH_FAILED; @@ -353,11 +483,14 @@ KOReaderSyncClient::Error KOReaderSyncClient::updateProgress(const KOReaderProgr } const char* KOReaderSyncClient::lastFailureDetail() { + const bool isUpload = (lastOperation && strcmp(lastOperation, "update progress") == 0); + const unsigned requiredContig = isUpload ? MIN_CONTIG_HEAP_FOR_TLS_UPLOAD : MIN_CONTIG_HEAP_FOR_TLS; + // Heap-pressure case: surfaced when checkHeapForTls() refused before any TCP/TLS work happened. if (lastEspError == ESP_ERR_NO_MEM && lastHttpCode == 0) { snprintf(g_failureDetailBuf, sizeof(g_failureDetailBuf), "%s: low memory (%u free, %u contig, need %u). Reboot device.", lastOperation, lastHeapAtFailure, - lastContigHeapAtFailure, MIN_CONTIG_HEAP_FOR_TLS); + lastContigHeapAtFailure, requiredContig); return g_failureDetailBuf; } // Network/TLS case: esp_http_client_perform() failed before getting a status code. diff --git a/lib/KOReaderSync/KOReaderSyncClient.h b/lib/KOReaderSync/KOReaderSyncClient.h index 3697c34a..d98e0423 100644 --- a/lib/KOReaderSync/KOReaderSyncClient.h +++ b/lib/KOReaderSync/KOReaderSyncClient.h @@ -70,6 +70,17 @@ class KOReaderSyncClient { */ static Error updateProgress(const KOReaderProgress& progress); + /** + * Keep HTTP/TLS session alive across multiple sync requests (GET/PUT). + * Intended for KOReaderSyncActivity to reduce repeated handshake churn. + */ + static void beginPersistentSession(); + + /** + * Close and release any persistent HTTP/TLS session. + */ + static void endPersistentSession(); + /** * Get human-readable error message (short, for status line). */ @@ -100,5 +111,6 @@ class KOReaderSyncClient { * a request. Below this, the client refuses with NETWORK_ERROR and lastFailureDetail * reports a heap-pressure message instead of attempting (and crashing) the TLS handshake. */ - static constexpr unsigned MIN_CONTIG_HEAP_FOR_TLS = 32 * 1024; + static constexpr unsigned MIN_CONTIG_HEAP_FOR_TLS = 36 * 1024; + static constexpr unsigned MIN_CONTIG_HEAP_FOR_TLS_UPLOAD = 34 * 1024; }; diff --git a/platformio.ini b/platformio.ini index 66bdf599..10696034 100644 --- a/platformio.ini +++ b/platformio.ini @@ -25,7 +25,7 @@ build_flags = -DEINK_DISPLAY_SINGLE_BUFFER_MODE=1 -DDISABLE_FS_H_WARNING=1 -DDESTRUCTOR_CLOSES_FILE=1 - ; -DENABLE_IMAGE_DITHERING_EXTENSION ; dont enable by default, as it increases code size and may not be needed for all images + ;-DENABLE_IMAGE_DITHERING_EXTENSION ; dont enable by default, as it increases code size and may not be needed for all images # https://libexpat.github.io/doc/api/latest/#XML_GE -DXML_GE=0 -DXML_CONTEXT_BYTES=1024 diff --git a/scripts/generate_test_epub.py b/scripts/generate_test_epub.py index 6f8594d8..d8a7f4db 100644 --- a/scripts/generate_test_epub.py +++ b/scripts/generate_test_epub.py @@ -5,7 +5,6 @@ Generate test EPUBs for rendering verification. Creates EPUBs to verify: - Image: Grayscale rendering (4 levels), scaling, centering, cache performance - Text: pre element line breaks, blank lines, nested code element -- Layout: nested block margins, sibling style restoration, image wrapper spacing """ import os @@ -47,7 +46,7 @@ def get_font(size=20): for path in candidates: try: return ImageFont.truetype(path, size) - except Exception: + except: continue return ImageFont.load_default() @@ -555,7 +554,6 @@ def create_epub(epub_path, title, chapters): # Collect all images and chapters manifest_items = [] spine_items = [] - written_images = set() # Add chapters and images for i, (chapter_title, html_content, images) in enumerate(chapters): @@ -564,8 +562,6 @@ def create_epub(epub_path, title, chapters): # Add images for this chapter for img_filename, img_data in images: - if img_filename in written_images: - continue media_type = ( "image/png" if img_filename.endswith(".png") else "image/jpeg" ) @@ -573,7 +569,6 @@ def create_epub(epub_path, title, chapters): f' ' ) epub.writestr(f"OEBPS/images/{img_filename}", img_data) - written_images.add(img_filename) # Add chapter manifest_items.append( @@ -623,12 +618,12 @@ def create_epub(epub_path, title, chapters): epub.writestr("OEBPS/nav.xhtml", nav_xhtml) -def make_chapter(title, body_content, head_content=""): +def make_chapter(title, body_content): """Create XHTML chapter content.""" return f""" -{title}{head_content} +{title}

{title}

{body_content} @@ -1006,102 +1001,6 @@ def main(): OUTPUT_DIR / "test_mixed_images.epub", "Mixed Format Tests", mixed_chapters ) - print("Creating layout regression test EPUB...") - - layout_chapters = [ - ( - "Introduction", - make_chapter( - "Layout Regression Tests", - """ -

This EPUB exercises recent parser edge cases around nested block styles and image wrappers.

-

Recommended settings: Paragraph Alignment set to Book Style or Justify.

-

This regression EPUB uses inline style attributes rather than a head <style> block so it works even if chapter-local embedded CSS is not loaded.

-
    -
  • Nested horizontal margin inheritance for sibling blocks
  • -
  • Vertical paragraph spacing should not explode with nested wrappers
  • -
  • Image wrapper spacing should apply to the image, not leak into following text
  • -
  • Hidden images should not leave a large blank gap before the next paragraph
  • -
-""", - ), - [], - ), - ( - "1. Nested Horizontal Margins", - make_chapter( - "Nested Horizontal Margin Inheritance", - """ -

This chapter mirrors the c1/c2/c3/c4 example behind PR 1582.

-

Expected: C3 is indented the most. C4 is indented less than C3, but still more than the baseline paragraph outside the wrapper.

-

Expected order of indentation: C3 > C4 > baseline paragraph.

-
-
-

C3 paragraph. This text should have the largest left indent because it inherits the outer wrapper, the inner wrapper, and its own left margin. Repeat text to make the paragraph wrap across multiple lines and make the effective left inset obvious while reading.

-
-

C4 paragraph. This text should still inherit the outer wrapper indent, but not the inner wrapper indent. It should therefore appear less indented than the paragraph above, not flush with the body text.

-

Outer-wrapper-only control paragraph. This paragraph should still be indented relative to the page body because it inherits the outer wrapper margin, even though it has no paragraph-level margin-left of its own.

-
-

Baseline paragraph outside the wrappers. This paragraph should align with the normal body text and should be the least indented paragraph on this page.

-""", - ), - [], - ), - ( - "2. Nested Vertical Margins", - make_chapter( - "Nested Vertical Margin Sanity", - """ -

Expected: wrapper nesting should not create an oversized blank vertical gulf between these paragraphs.

-
-
-

Nested vertical spacing paragraph. There should be some breathing room above and below, but not dramatically more than a normal section break.

-
-

Sibling paragraph after the nested block. Spacing before this paragraph should feel normal and should not keep growing with every ancestor wrapper.

-
-

Baseline paragraph after the wrapper section. This should not be pushed far down the page.

-""", - ), - [], - ), - ( - "3. Image Wrapper Spacing", - make_chapter( - "Image Wrapper Spacing", - """ -

Expected: the wrapper's margins should create space around the image, and the paragraph after the image should start with normal spacing rather than inheriting a second copy of that gap.

-
-
-

Wrapped image spacing test

-
-
-

Paragraph after wrapped image. If the wrapper spacing leaks, this paragraph will begin too far down the page. If container width is ignored, the image may also appear too wide for the wrapper.

-""", - ), - [("centering_test.jpg", images["centering_test.jpg"])], - ), - ( - "4. Hidden Image Spacing", - make_chapter( - "Hidden Image Spacing Reset", - """ -

Expected: the hidden image wrapper should not leave a large blank gap before the following paragraph.

-
-

This image is intentionally hidden by CSS

-
-

Paragraph after hidden image. This should follow with near-normal spacing, not the large gap that would be appropriate for a visible wrapped image.

-""", - ), - [("centering_test.jpg", images["centering_test.jpg"])], - ), - ] - - create_epub( - OUTPUT_DIR / "test_layout_regressions.epub", - "Layout Regression Tests", - layout_chapters, - ) - print("Creating text rendering test EPUB...") text_chapters = [ ( diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index 833600d1..2cce6c0d 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -148,11 +148,7 @@ void EpubReaderActivity::loop() { // Without credentials, fall through to the regular menu on release. if (mappedInput.isPressed(MappedInputManager::Button::Confirm) && mappedInput.getHeldTime() >= ReaderUtils::GO_HOME_MS && KOREADER_STORE.hasCredentials()) { - const int currentPage = section ? section->currentPage : 0; - const int totalPages = section ? section->pageCount : 0; - startActivityForResult(std::make_unique(renderer, mappedInput, epub, epub->getPath(), - currentSpineIndex, currentPage, totalPages), - [this](const ActivityResult& result) { handleSyncResult(result); }); + launchKOReaderSync(); return; } @@ -464,18 +460,64 @@ void EpubReaderActivity::onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction } case EpubReaderMenuActivity::MenuAction::SYNC: { if (KOREADER_STORE.hasCredentials()) { - const int currentPage = section ? section->currentPage : 0; - const int totalPages = section ? section->pageCount : 0; - startActivityForResult(std::make_unique(renderer, mappedInput, epub, epub->getPath(), - currentSpineIndex, currentPage, totalPages), - [this](const ActivityResult& result) { handleSyncResult(result); }); + launchKOReaderSync(); } break; } } } +void EpubReaderActivity::launchKOReaderSync() { + if (!epub) { + return; + } + + const std::string syncEpubPath = epub->getPath(); + const int currentPage = section ? section->currentPage : 0; + const int totalPages = section ? section->pageCount : 0; + + { + // Drop large reader state before TLS-heavy sync to improve contiguous heap + // and reduce long-run fragmentation across repeated sync attempts. + RenderLock lock(*this); + nextPageNumber = currentPage; + cachedSpineIndex = currentSpineIndex; + cachedChapterTotalPageCount = totalPages; + section.reset(); + epub.reset(); + currentPageFootnotes.clear(); + currentPageFootnotes.shrink_to_fit(); + } + deferredSyncEpubPath = syncEpubPath; + + renderer.cleanupGrayscaleWithFrameBuffer(); + if (auto* cacheManager = renderer.getFontCacheManager()) { + cacheManager->clearCache(); + cacheManager->resetStats(); + } + + LOG_DBG("ERS", "Pre-sync trim: spine=%d page=%d/%d heap=%lu", currentSpineIndex, currentPage, totalPages, + static_cast(esp_get_free_heap_size())); + + startActivityForResult(std::make_unique(renderer, mappedInput, std::shared_ptr{}, + syncEpubPath, + currentSpineIndex, currentPage, totalPages), + [this](const ActivityResult& result) { handleSyncResult(result); }); +} + void EpubReaderActivity::handleSyncResult(const ActivityResult& result) { + if (!epub && !deferredSyncEpubPath.empty()) { + epub = std::make_shared(deferredSyncEpubPath, "/.crosspoint"); + if (!epub->load(true, true)) { + LOG_ERR("ERS", "Failed to reload EPUB after sync: %s", deferredSyncEpubPath.c_str()); + finish(); + return; + } + epub->setupCacheDir(); + LOG_DBG("ERS", "Reloaded EPUB after sync: %s", deferredSyncEpubPath.c_str()); + deferredSyncEpubPath.clear(); + } + if (!result.isCancelled) { const auto& sync = std::get(result.data); if (currentSpineIndex != sync.spineIndex || (section && section->currentPage != sync.page)) { diff --git a/src/activities/reader/EpubReaderActivity.h b/src/activities/reader/EpubReaderActivity.h index 3467828b..5d6f41c8 100644 --- a/src/activities/reader/EpubReaderActivity.h +++ b/src/activities/reader/EpubReaderActivity.h @@ -35,6 +35,7 @@ class EpubReaderActivity final : public Activity { bool pendingScreenshot = false; bool skipNextButtonCheck = false; // Skip button processing for one frame after subactivity exit bool automaticPageTurnActive = false; + std::string deferredSyncEpubPath; // -1 means use global SETTINGS value. int8_t bookEmbeddedStyleOverride = -1; int8_t bookImageRenderingOverride = -1; @@ -57,6 +58,7 @@ class EpubReaderActivity final : public Activity { // Jump to a percentage of the book (0-100), mapping it to spine and page. void jumpToPercent(int percent); void onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction action); + void launchKOReaderSync(); void handleSyncResult(const ActivityResult& result); void applyOrientation(uint8_t orientation); void toggleAutoPageTurn(uint8_t selectedPageTurnOption); diff --git a/src/activities/reader/KOReaderSyncActivity.cpp b/src/activities/reader/KOReaderSyncActivity.cpp index 46333b14..9167db42 100644 --- a/src/activities/reader/KOReaderSyncActivity.cpp +++ b/src/activities/reader/KOReaderSyncActivity.cpp @@ -4,7 +4,10 @@ #include #include #include +#include #include +#include +#include #include "KOReaderCredentialStore.h" #include "KOReaderDocumentId.h" @@ -13,6 +16,45 @@ #include "components/UITheme.h" #include "fontIds.h" +namespace { +constexpr time_t NTP_RESYNC_MIN_INTERVAL_SEC = 15 * 60; + +// Emits heap snapshots around sync stages so we can correlate TLS failures with +// fragmentation and not just total free heap. +void logSyncMemSnapshot(const char* stage) { + const uint32_t freeHeap = esp_get_free_heap_size(); + const uint32_t contigHeap = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_DEFAULT); + const bool integrityOk = heap_caps_check_integrity_all(true); + LOG_DBG("KOSync", "Sync mem[%s]: free=%lu contig=%lu integrity=%s", stage, freeHeap, contigHeap, + integrityOk ? "ok" : "fail"); +} + +// Frees renderer-owned caches right before network work. +// Why: TLS handshake needs a large contiguous block, and font cache memory can +// increase fragmentation even when total free heap looks acceptable. +void trimMemoryBeforeTls(GfxRenderer& renderer) { + if (auto* cacheManager = renderer.getFontCacheManager()) { + cacheManager->clearCache(); + cacheManager->resetStats(); + LOG_DBG("KOSync", "Cleared font cache before TLS"); + } +} + +bool shouldSyncNtpNow() { + const time_t lastSync = HalClock::lastSyncTime(); + const time_t now = HalClock::now(); + if (lastSync <= 0 || now <= 0) { + return true; + } + + const time_t age = now - lastSync; + if (age < 0) { + return true; + } + return age >= NTP_RESYNC_MIN_INTERVAL_SEC; +} +} // namespace + void KOReaderSyncActivity::onWifiSelectionComplete(const bool success) { if (!success) { LOG_DBG("KOSync", "WiFi connection failed, exiting"); @@ -30,18 +72,29 @@ void KOReaderSyncActivity::onWifiSelectionComplete(const bool success) { state = SYNCING; statusMessage = tr(STR_SYNCING_TIME); } - requestUpdate(true); + requestUpdate(); - // Sync time with NTP before making API requests - HalClock::syncNtp(); + // Avoid repeated NTP churn during rapid sync retries; it can fragment heap + // right before TLS. Re-sync only when clock is stale. + if (shouldSyncNtpNow()) { + HalClock::syncNtp(); + } else { + LOG_DBG("KOSync", "Skipping NTP sync (recently synced)"); + } { RenderLock lock(*this); statusMessage = tr(STR_CALC_HASH); } - requestUpdate(true); + requestUpdate(); + + logSyncMemSnapshot("before_performSync"); + trimMemoryBeforeTls(renderer); + logSyncMemSnapshot("after_trim_before_performSync"); performSync(); + + logSyncMemSnapshot("after_performSync"); } void KOReaderSyncActivity::performSync() { @@ -63,16 +116,34 @@ void KOReaderSyncActivity::performSync() { LOG_DBG("KOSync", "Document hash: %s", documentHash.c_str()); + // Precompute local mapping before first network request so the expensive + // inflate/index work happens before TLS. This avoids a second local mapping + // pass later and keeps the upload path lightweight. + { + RenderLock lock(*this); + statusMessage = tr(STR_MAPPING_LOCAL); + } + requestUpdateAndWait(); + computeLocalProgressAndChapter(); + + // Drop EPUB state before HTTPS to maximize contiguous heap for TLS. + releaseEpubForMapping(); + { RenderLock lock(*this); statusMessage = tr(STR_FETCH_PROGRESS); } - requestUpdateAndWait(); + requestUpdate(); + + // Keep the GET connection alive so Upload can reuse the same session and + // avoid a second TLS handshake under fragmented heap. + KOReaderSyncClient::beginPersistentSession(); // Fetch remote progress const auto result = KOReaderSyncClient::getProgress(documentHash, remoteProgress); if (result == KOReaderSyncClient::NOT_FOUND) { + // Keep session open so an immediate upload can reuse the same connection. // No remote progress - offer to upload { RenderLock lock(*this); @@ -84,6 +155,7 @@ void KOReaderSyncActivity::performSync() { } if (result != KOReaderSyncClient::OK) { + KOReaderSyncClient::endPersistentSession(); { RenderLock lock(*this); state = SYNC_FAILED; @@ -100,27 +172,25 @@ void KOReaderSyncActivity::performSync() { return; } - // Convert remote progress to CrossPoint position + // Defer remote EPUB mapping until user chooses Apply. Upload only needs the + // precomputed local XPath, so this avoids post-fetch inflate churn and keeps + // the GET session reusable for PUT. hasRemoteProgress = true; - { - RenderLock lock(*this); - statusMessage = tr(STR_MAPPING_REMOTE); + remotePositionMapped = false; + remotePosition.spineIndex = currentSpineIndex; + remotePosition.pageNumber = 0; + remotePosition.totalPages = 0; + remotePosition.paragraphIndex = 0; + remotePosition.hasParagraphIndex = false; + int xpathSpineIndex = -1; + if (ChapterXPathIndexer::tryExtractSpineIndexFromXPath(remoteProgress.progress, xpathSpineIndex) && + xpathSpineIndex >= 0) { + remotePosition.spineIndex = xpathSpineIndex; } - requestUpdateAndWait(); + remoteChapterLabel = tr(STR_UNNAMED); - KOReaderPosition koPos = {remoteProgress.progress, remoteProgress.percentage}; - remotePosition = ProgressMapper::toCrossPoint(epub, koPos, currentSpineIndex, totalPagesInSpine); - - // Calculate local progress in KOReader format (for display) - { - RenderLock lock(*this); - statusMessage = tr(STR_MAPPING_LOCAL); - } - requestUpdateAndWait(); - - CrossPointPosition localPos = {currentSpineIndex, currentPage, totalPagesInSpine, localParagraphIndex, - hasLocalParagraphIndex}; - localProgress = ProgressMapper::toKOReader(epub, localPos); + // Local progress was precomputed before network; keep using the cached value. + releaseEpubForMapping(); { RenderLock lock(*this); @@ -144,17 +214,46 @@ void KOReaderSyncActivity::performUpload() { } requestUpdateAndWait(); - // Convert current position to KOReader format - CrossPointPosition localPos = {currentSpineIndex, currentPage, totalPagesInSpine, localParagraphIndex, - hasLocalParagraphIndex}; - KOReaderPosition koPos = ProgressMapper::toKOReader(epub, localPos); + // If sync reached this screen without cached local progress, compute it now. + // This keeps upload robust when UI flow changes or retries happen. + if (localProgress.xpath.empty()) { + computeLocalProgressAndChapter(); + releaseEpubForMapping(); + } + + // Hard-stop if we still have no xpath: sending an empty progress payload would + // be ambiguous server-side and hides the real local mapping failure. + if (localProgress.xpath.empty()) { + { + RenderLock lock(*this); + state = SYNC_FAILED; + statusMessage = tr(STR_SYNC_FAILED_MSG); + } + requestUpdate(true); + return; + } + + // Result screen rendering repopulates glyph caches; trim again right before + // the upload handshake to maximize contiguous heap for TLS. + trimMemoryBeforeTls(renderer); + logSyncMemSnapshot("after_trim_before_updateProgress"); + + // Capture upload-phase memory separately from fetch phase to diagnose failures + // that only appear on PUT due to allocator state changes. + logSyncMemSnapshot("before_updateProgress"); + + // Ensure a session exists for upload. When GET succeeded, this should reuse + // the existing connection and typically skip a second handshake. + KOReaderSyncClient::beginPersistentSession(); KOReaderProgress progress; progress.document = documentHash; - progress.progress = koPos.xpath; - progress.percentage = koPos.percentage; + progress.progress = localProgress.xpath; + progress.percentage = localProgress.percentage; const auto result = KOReaderSyncClient::updateProgress(progress); + KOReaderSyncClient::endPersistentSession(); + logSyncMemSnapshot("after_updateProgress"); if (result != KOReaderSyncClient::OK) { HalClock::wifiOff(true); @@ -209,6 +308,7 @@ void KOReaderSyncActivity::onEnter() { void KOReaderSyncActivity::onExit() { Activity::onExit(); + KOReaderSyncClient::endPersistentSession(); HalClock::wifiOff(true); } @@ -251,14 +351,8 @@ void KOReaderSyncActivity::render(RenderLock&&) { renderer.drawCenteredText(UI_10_FONT_ID, 120, tr(STR_PROGRESS_FOUND), true, EpdFontFamily::BOLD); // Get chapter names from TOC - const int remoteTocIndex = epub->getTocIndexForSpineIndex(remotePosition.spineIndex); - const int localTocIndex = epub->getTocIndexForSpineIndex(currentSpineIndex); - const std::string remoteChapter = - (remoteTocIndex >= 0) ? epub->getTocItem(remoteTocIndex).title - : (std::string(tr(STR_SECTION_PREFIX)) + std::to_string(remotePosition.spineIndex + 1)); - const std::string localChapter = - (localTocIndex >= 0) ? epub->getTocItem(localTocIndex).title - : (std::string(tr(STR_SECTION_PREFIX)) + std::to_string(currentSpineIndex + 1)); + const std::string& remoteChapter = remoteChapterLabel; + const std::string& localChapter = localChapterLabel; // Remote progress - chapter and page renderer.drawText(UI_10_FONT_ID, contentRect.x + 20, 160, tr(STR_REMOTE_LABEL), true); @@ -339,6 +433,76 @@ void KOReaderSyncActivity::render(RenderLock&&) { } } +bool KOReaderSyncActivity::ensureEpubLoadedForMapping() { + if (epub) { + return true; + } + + // Reload on demand to keep steady-state sync memory low. Mapping and chapter + // lookup need EPUB metadata; TLS steps do not. + epub = std::make_shared(epubPath, "/.crosspoint"); + if (!epub->load(true, true)) { + LOG_ERR("KOSync", "Failed to reload EPUB for mapping: %s", epubPath.c_str()); + epub.reset(); + return false; + } + epub->setupCacheDir(); + return true; +} + +bool KOReaderSyncActivity::ensureRemotePositionMapped() { + if (remotePositionMapped) { + return true; + } + + // Apply needs remote->local mapping, which triggers EPUB inflate work. + // Release HTTP/TLS session first so mapping has maximum heap headroom. + KOReaderSyncClient::endPersistentSession(); + + { + RenderLock lock(*this); + statusMessage = tr(STR_MAPPING_REMOTE); + } + requestUpdateAndWait(); + + KOReaderPosition koPos = {remoteProgress.progress, remoteProgress.percentage}; + if (!ensureEpubLoadedForMapping()) { + return false; + } + remotePosition = ProgressMapper::toCrossPoint(epub, koPos, currentSpineIndex, totalPagesInSpine); + computeRemoteChapter(); + releaseEpubForMapping(); + remotePositionMapped = true; + return true; +} + +void KOReaderSyncActivity::releaseEpubForMapping() { epub.reset(); } + +void KOReaderSyncActivity::computeLocalProgressAndChapter() { + if (!ensureEpubLoadedForMapping()) { + return; + } + + CrossPointPosition localPos = {currentSpineIndex, currentPage, totalPagesInSpine, localParagraphIndex, + hasLocalParagraphIndex}; + localProgress = ProgressMapper::toKOReader(epub, localPos); + + const int localTocIndex = epub->getTocIndexForSpineIndex(currentSpineIndex); + localChapterLabel = + (localTocIndex >= 0) ? epub->getTocItem(localTocIndex).title + : (std::string(tr(STR_SECTION_PREFIX)) + std::to_string(currentSpineIndex + 1)); +} + +void KOReaderSyncActivity::computeRemoteChapter() { + if (!epub) { + return; + } + const int remoteTocIndex = epub->getTocIndexForSpineIndex(remotePosition.spineIndex); + remoteChapterLabel = + (remoteTocIndex >= 0) ? epub->getTocItem(remoteTocIndex).title + : (std::string(tr(STR_SECTION_PREFIX)) + std::to_string(remotePosition.spineIndex + 1)); +} + void KOReaderSyncActivity::loop() { if (state == NO_CREDENTIALS || state == SYNC_FAILED || state == UPLOAD_COMPLETE) { if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { @@ -366,6 +530,15 @@ void KOReaderSyncActivity::loop() { if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { if (selectedOption == 0) { + if (!ensureRemotePositionMapped()) { + { + RenderLock lock(*this); + state = SYNC_FAILED; + statusMessage = tr(STR_SYNC_FAILED_MSG); + } + requestUpdate(true); + return; + } // Wifi will be turned off in onExit() setResult(SyncResult{remotePosition.spineIndex, remotePosition.pageNumber, remotePosition.paragraphIndex, remotePosition.hasParagraphIndex}); diff --git a/src/activities/reader/KOReaderSyncActivity.h b/src/activities/reader/KOReaderSyncActivity.h index fd02d861..6edb8fc2 100644 --- a/src/activities/reader/KOReaderSyncActivity.h +++ b/src/activities/reader/KOReaderSyncActivity.h @@ -4,6 +4,7 @@ #include #include +#include "ChapterXPathIndexer.h" #include "KOReaderSyncClient.h" #include "ProgressMapper.h" #include "activities/Activity.h" @@ -69,11 +70,14 @@ class KOReaderSyncActivity final : public Activity { // Remote progress data bool hasRemoteProgress = false; + bool remotePositionMapped = false; KOReaderProgress remoteProgress; CrossPointPosition remotePosition; // Local progress as KOReader format (for display) KOReaderPosition localProgress; + std::string remoteChapterLabel; + std::string localChapterLabel; // Selection in result screen (0=Apply, 1=Upload) int selectedOption = 0; @@ -86,4 +90,9 @@ class KOReaderSyncActivity final : public Activity { void performSync(); void performUpload(); void closeCancelled(); + bool ensureEpubLoadedForMapping(); + void releaseEpubForMapping(); + void computeLocalProgressAndChapter(); + void computeRemoteChapter(); + bool ensureRemotePositionMapped(); }; diff --git a/test/epubs/test_jpeg_images.epub b/test/epubs/test_jpeg_images.epub index 2bfc04c72fec91e8896ed35bba1121337c5c99be..a99251f06497a11a11e9b80dd92da6d661b89b43 100644 GIT binary patch delta 320103 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 z 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 O2kStuobIa9 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