Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ class ChatMessageSyncer @Inject constructor(
*
* [newestPersistedMessage] is the newest persisted message that qualifies as a conversation's
* last message (system messages that never change a conversation's preview are skipped). It
* feeds the conversation list update after a background catch-up.
* feeds the conversation list update after a background catch-up. [newestMessageRequestedAtNanos]
* is the [System.nanoTime] at which the request that fetched it was started.
*
* [visibleMessageIds] are the ids of all persisted messages of this round that render as their
* own bubble in an open chat (see [CHAT_HIDDEN_SYSTEM_MESSAGE_TYPES] β€” a different, broader
Expand All @@ -115,7 +116,8 @@ class ChatMessageSyncer @Inject constructor(
val persistedMessageCount: Int = 0,
val syncFailed: Boolean = false,
val newestPersistedMessage: ChatMessageDto? = null,
val visibleMessageIds: List<Long> = emptyList()
val visibleMessageIds: List<Long> = emptyList(),
val newestMessageRequestedAtNanos: Long? = null
)

/**
Expand Down Expand Up @@ -507,7 +509,12 @@ class ChatMessageSyncer @Inject constructor(
oldestPersistedMessageId = anchorOutcome.oldestPersistedMessageId,
persistedMessageCount = anchorOutcome.persistedMessageCount + backlogOutcome.persistedMessageCount,
syncFailed = backlogOutcome.syncFailed,
newestPersistedMessage = backlogOutcome.newestPersistedMessage ?: anchorOutcome.newestPersistedMessage
newestPersistedMessage = backlogOutcome.newestPersistedMessage ?: anchorOutcome.newestPersistedMessage,
newestMessageRequestedAtNanos = if (backlogOutcome.newestPersistedMessage != null) {
backlogOutcome.newestMessageRequestedAtNanos
} else {
anchorOutcome.newestMessageRequestedAtNanos
}
)
}

Expand Down Expand Up @@ -539,6 +546,7 @@ class ChatMessageSyncer @Inject constructor(
var oldestPersisted: Long? = null
var newestPersisted: Long? = null
var newestPersistedMessage: ChatMessageDto? = null
var newestMessageRequestedAtNanos: Long? = null

repeat(MAX_BACKLOG_ROUNDS) {
val fieldMap = buildFieldMap(
Expand All @@ -558,7 +566,10 @@ class ChatMessageSyncer @Inject constructor(
totalCount += roundOutcome.persistedMessageCount
oldestPersisted = oldestPersisted ?: roundOutcome.oldestPersistedMessageId
newestPersisted = roundOutcome.newestPersistedMessageId ?: newestPersisted
newestPersistedMessage = roundOutcome.newestPersistedMessage ?: newestPersistedMessage
if (roundOutcome.newestPersistedMessage != null) {
newestPersistedMessage = roundOutcome.newestPersistedMessage
newestMessageRequestedAtNanos = roundOutcome.newestMessageRequestedAtNanos
}
}

val caughtUp = !roundOutcome.persistedNewMessages || roundOutcome.persistedMessageCount < limit
Expand All @@ -570,7 +581,8 @@ class ChatMessageSyncer @Inject constructor(
oldestPersistedMessageId = oldestPersisted,
persistedMessageCount = totalCount,
syncFailed = roundOutcome.syncFailed,
newestPersistedMessage = newestPersistedMessage
newestPersistedMessage = newestPersistedMessage,
newestMessageRequestedAtNanos = newestMessageRequestedAtNanos
)
}
anchor = nextAnchor
Expand Down Expand Up @@ -603,7 +615,12 @@ class ChatMessageSyncer @Inject constructor(
oldestPersistedMessageId = fallbackOutcome.oldestPersistedMessageId,
persistedMessageCount = fallbackOutcome.persistedMessageCount,
syncFailed = fallbackOutcome.syncFailed,
newestPersistedMessage = fallbackOutcome.newestPersistedMessage ?: newestPersistedMessage
newestPersistedMessage = fallbackOutcome.newestPersistedMessage ?: newestPersistedMessage,
newestMessageRequestedAtNanos = if (fallbackOutcome.newestPersistedMessage != null) {
fallbackOutcome.newestMessageRequestedAtNanos
} else {
newestMessageRequestedAtNanos
}
)
}

Expand Down Expand Up @@ -636,7 +653,7 @@ class ChatMessageSyncer @Inject constructor(
var totalCount = 0
var oldestPersisted: Long? = null
var newestPersisted: Long? = null
var newestPersistedMessage: ChatMessageDto? = null
var newestMessageOutcome: SyncOutcome? = null

repeat(MAX_VISIBLE_MESSAGE_ROUNDS) {
val roundOutcome = pullAndPersistMessages(target, fieldMap, events)
Expand All @@ -653,7 +670,7 @@ class ChatMessageSyncer @Inject constructor(
}
val foundNewVisibleMessage = roundOutcome.visibleMessageIds.any { it != knownAnchorId }
if (foundNewVisibleMessage) {
newestPersistedMessage = roundOutcome.newestPersistedMessage
newestMessageOutcome = roundOutcome
}

val nextAnchor = if (lookIntoFuture) {
Expand All @@ -670,7 +687,8 @@ class ChatMessageSyncer @Inject constructor(
oldestPersistedMessageId = oldestPersisted,
persistedMessageCount = totalCount,
syncFailed = roundOutcome.syncFailed,
newestPersistedMessage = newestPersistedMessage
newestPersistedMessage = newestMessageOutcome?.newestPersistedMessage,
newestMessageRequestedAtNanos = newestMessageOutcome?.newestMessageRequestedAtNanos
)
}

Expand All @@ -689,7 +707,8 @@ class ChatMessageSyncer @Inject constructor(
newestPersistedMessageId = newestPersisted,
oldestPersistedMessageId = oldestPersisted,
persistedMessageCount = totalCount,
newestPersistedMessage = newestPersistedMessage
newestPersistedMessage = newestMessageOutcome?.newestPersistedMessage,
newestMessageRequestedAtNanos = newestMessageOutcome?.newestMessageRequestedAtNanos
)
}

Expand Down Expand Up @@ -721,14 +740,16 @@ class ChatMessageSyncer @Inject constructor(
var attempts = 1

while (attempts < MAX_PULL_ATTEMPTS) {
val requestedAtNanos = System.nanoTime()
runCatching {
network.pullChatMessages(target.credentials, target.urlForChatting, fieldMap)
}.fold(
onSuccess = { response ->
val result = when (response.code()) {
HTTP_CODE_OK -> ChatPullResult.Success(
messages = response.body()?.ocs?.data.orEmpty(),
lastCommonRead = response.headers()["X-Chat-Last-Common-Read"]?.toInt()
lastCommonRead = response.headers()["X-Chat-Last-Common-Read"]?.toInt(),
requestedAtNanos = requestedAtNanos
)
HTTP_CODE_NOT_MODIFIED -> ChatPullResult.NotModified
HTTP_CODE_PRECONDITION_FAILED -> ChatPullResult.PreconditionFailed
Expand Down Expand Up @@ -857,7 +878,8 @@ class ChatMessageSyncer @Inject constructor(
oldestPersistedMessageId = persistedMessages.minOfOrNull { it.id },
persistedMessageCount = persistedMessages.size,
newestPersistedMessage = previewEligibleMessages.maxByOrNull { it.id },
visibleMessageIds = chatVisibleMessages.map { it.id }
visibleMessageIds = chatVisibleMessages.map { it.id },
newestMessageRequestedAtNanos = result.requestedAtNanos
)
} else {
Log.d(TAG, "No new messages to update")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ package com.nextcloud.talk.chat.domain
import com.nextcloud.talk.models.json.chat.ChatMessageDto

sealed class ChatPullResult {
data class Success(val messages: List<ChatMessageDto>, val lastCommonRead: Int?) : ChatPullResult()
/** [requestedAtNanos] is the [System.nanoTime] at which the request that got the response was started. */
data class Success(val messages: List<ChatMessageDto>, val lastCommonRead: Int?, val requestedAtNanos: Long) :
ChatPullResult()

object NotModified : ChatPullResult()
object PreconditionFailed : ChatPullResult()
Expand Down
Loading
Loading