From b3c6acd0078af58d3ee0059e7697fc6a36583f19 Mon Sep 17 00:00:00 2001 From: k1ngsterr1 Date: Fri, 27 Feb 2026 19:20:11 +0500 Subject: [PATCH] feat: Update Android build workflow to run on Linux and enhance sync cycle handling in ProtocolManager --- .gitea/workflows/android.yaml | 2 +- .../messenger/network/ProtocolManager.kt | 29 ++++++++++++++----- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/.gitea/workflows/android.yaml b/.gitea/workflows/android.yaml index f9f51ee..915bd0a 100644 --- a/.gitea/workflows/android.yaml +++ b/.gitea/workflows/android.yaml @@ -14,7 +14,7 @@ on: jobs: build: - runs-on: android-builders + runs-on: linux steps: - name: Checkout code uses: actions/checkout@v6 diff --git a/app/src/main/java/com/rosetta/messenger/network/ProtocolManager.kt b/app/src/main/java/com/rosetta/messenger/network/ProtocolManager.kt index 56b2b1f..804f4bb 100644 --- a/app/src/main/java/com/rosetta/messenger/network/ProtocolManager.kt +++ b/app/src/main/java/com/rosetta/messenger/network/ProtocolManager.kt @@ -550,6 +550,13 @@ object ProtocolManager { subscribePushTokenIfAvailable() } + private fun finishSyncCycle(reason: String) { + addLog(reason) + setSyncInProgress(false) + retryWaitingMessages() + requestMissingUserInfo() + } + /** * Send FCM push token to server (SUBSCRIBE). * Deduplicates: won't re-send the same token within one connection session. @@ -689,6 +696,19 @@ object ProtocolManager { else -> 0L } + // Loop guard: if server keeps BATCH_END with unchanged cursor and we did not + // process anything in this batch, treat sync as finished to avoid infinite loop. + val noProgress = + failuresInBatch == 0 && + processedMaxTimestamp <= 0L && + (nextCursor <= 0L || nextCursor == currentCursor) + if (noProgress) { + finishSyncCycle( + "✅ SYNC COMPLETE — no progress on batch (server=$safeBatchTimestamp, current=$currentCursor)" + ) + return@launch + } + // If server batch timestamp runs ahead of what we actually processed, clamp it. // This avoids skipping tail messages when packet delivery/parsing was partial. if (processedMaxTimestamp > 0L && processedMaxTimestamp < safeBatchTimestamp) { @@ -709,18 +729,11 @@ object ProtocolManager { } } SyncStatus.NOT_NEEDED -> { - addLog("✅ SYNC COMPLETE — no more messages to sync") // Synchronous — immediately marks sync as complete. // Desktop parity: NOT_NEEDED just sets state to CONNECTED, // does NOT update last_sync timestamp (unnecessary since client // was already up to date). - setSyncInProgress(false) - // Retry any messages stuck in WAITING status from previous sessions. - retryWaitingMessages() - // Desktop parity: resolve names for all dialogs with empty titles. - // Desktop does this per-component via useUserInformation hook; - // we batch it after sync for efficiency. - requestMissingUserInfo() + finishSyncCycle("✅ SYNC COMPLETE — no more messages to sync") } } }