From 656505eda76ad4eb195da2b60b350797a7b8c8d0 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Sat, 22 Aug 2026 09:57:26 -0400 Subject: [PATCH] fix(sync): report interactive push/pull failures when offline An interactive pull could exit without any feedback while push showed 'Failed to push progress', from two silent exits on the pull path: - pulling an unlinked book delegated to a non-interactive push whose failure produced no UI (and could be swallowed by the 25s debounce) - when the device is connected at the IP level but has no internet, NetworkMgr:willRerunWhenOnline drops the callback with neither a rerun nor any UI (it only guarantees isConnected) Now the connected-but-offline state is detected up front and reported ('No internet connection. Progress was not pulled/pushed.'), resolve failures notify interactively, pulling with progress sync disabled explains itself instead of silently returning, and the generic pull failure message mentions the network connection like push does. --- main.lua | 67 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/main.lua b/main.lua index 250c909..6591c13 100644 --- a/main.lua +++ b/main.lua @@ -990,7 +990,15 @@ function Bookhoard:updateProgress(ensure_networking, interactive) return end - if not self.settings.sync_progress then return end + if not self.settings.sync_progress then + if interactive then + UIManager:show(InfoMessage:new{ + text = _("Reading progress sync is disabled (see What to sync)."), + timeout = 3, + }) + end + return + end if not self.ui.document then if interactive then @@ -1007,9 +1015,19 @@ function Bookhoard:updateProgress(ensure_networking, interactive) return end - if ensure_networking - and NetworkMgr:willRerunWhenOnline(function() self:updateProgress(ensure_networking, interactive) end) then - return + if ensure_networking then + -- Same silent-drop case as getProgress: connected but no internet + -- means willRerunWhenOnline neither reruns nor shows any UI. + if interactive and NetworkMgr:isConnected() and not NetworkMgr:isOnline() then + UIManager:show(InfoMessage:new{ + text = _("No internet connection. Progress was not pushed."), + timeout = 3, + }) + return + end + if NetworkMgr:willRerunWhenOnline(function() self:updateProgress(ensure_networking, interactive) end) then + return + end end UIManager:scheduleIn(0.5, function() @@ -1078,30 +1096,53 @@ function Bookhoard:getProgress(ensure_networking, interactive) return end - if not self.settings.sync_progress then return end + if not self.settings.sync_progress then + if interactive then + UIManager:show(InfoMessage:new{ + text = _("Reading progress sync is disabled (see What to sync)."), + timeout = 3, + }) + end + return + end local now = UIManager:getElapsedTimeSinceBoot() if not interactive and now - self.pull_timestamp <= API_CALL_DEBOUNCE_DELAY then return end - if ensure_networking - and NetworkMgr:willRerunWhenOnline(function() self:getProgress(ensure_networking, interactive) end) then - return + if ensure_networking then + -- willRerunWhenOnline silently drops the action (no rerun, no UI) + -- when the device is connected at the IP level but has no internet + -- access: it only guarantees isConnected, and in that state the + -- framework re-connects without ever invoking the callback. Catch + -- that state up front so an interactive pull never no-ops silently. + if interactive and NetworkMgr:isConnected() and not NetworkMgr:isOnline() then + UIManager:show(InfoMessage:new{ + text = _("No internet connection. Progress was not pulled."), + timeout = 3, + }) + return + end + if NetworkMgr:willRerunWhenOnline(function() self:getProgress(ensure_networking, interactive) end) then + return + end end local book_uuid = self:getBookhoardUUID() if not book_uuid then - -- No cached UUID yet (first open of a freshly downloaded book). Bootstrap - -- it by pushing once: the server resolves the book by SHA-256 and returns - -- the UUID, which the push handler caches. Then retry the pull. + -- No cached UUID yet (first open of a freshly downloaded book). Link + -- the book with a read-only SHA-256 lookup, then pull. Progress is + -- never pushed here: the device sits on the first page of a book the + -- server may hold mid-read, and pushing that would overwrite/server- + -- conflict the real progress before the pull could deliver it. if interactive then UIManager:show(InfoMessage:new{ text = _("Linking this book to Bookhoard first…"), timeout = 3, }) end - self:_bootstrapUUIDThenPull(interactive) + self:_linkBookThenPull(interactive) return end @@ -1201,7 +1242,7 @@ function Bookhoard:_doGetProgress(interactive) if not ok or not result then if interactive then UIManager:show(InfoMessage:new{ - text = _("Failed to pull progress."), + text = _("Failed to pull progress. Check your network connection."), timeout = 3, }) end