mirror of
https://github.com/nextcloud/talk-android
synced 2025-08-03 18:15:40 +01:00
check if sync succeeded
Decrease message limit for retries of message loading make it possible to add any amount (up to 100) of messages to UI for initial loading. add logging only make initial request for chat messages when newest message from DB is not equal the lastReadMessage that is offered by the conversation Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
parent
a331ba6372
commit
818a843143
@ -108,26 +108,63 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
override fun loadInitialMessages(withNetworkParams: Bundle): Job =
|
||||
scope.launch {
|
||||
Log.d(TAG, "---- loadInitialMessages ------------")
|
||||
Log.d(TAG, "conversationModel.internalId: " + conversationModel.internalId)
|
||||
|
||||
newXChatLastCommonRead = conversationModel.lastCommonReadMessage
|
||||
|
||||
val fieldMap = getFieldMap(
|
||||
lookIntoFuture = false,
|
||||
includeLastKnown = true,
|
||||
setReadMarker = true,
|
||||
lastKnown = null
|
||||
)
|
||||
withNetworkParams.putSerializable(BundleKeys.KEY_FIELD_MAP, fieldMap)
|
||||
withNetworkParams.putString(BundleKeys.KEY_ROOM_TOKEN, conversationModel.token)
|
||||
Log.d(TAG, "conversationModel.lastReadMessage:" + conversationModel.lastReadMessage)
|
||||
|
||||
sync(withNetworkParams)
|
||||
var newestMessageId = chatDao.getNewestMessageId(internalConversationId)
|
||||
Log.d(TAG, "newestMessageId: $newestMessageId")
|
||||
if (newestMessageId.toInt() == 0) {
|
||||
Log.d(TAG, "newestMessageId from db was 0. Must only happen when chat is loaded for the first time")
|
||||
}
|
||||
|
||||
val newestMessageId = chatDao.getNewestMessageId(internalConversationId)
|
||||
Log.d(TAG, "newestMessageId after sync: $newestMessageId")
|
||||
if (conversationModel.lastReadMessage.toLong() != newestMessageId) {
|
||||
Log.d(TAG, "An online request is made because chat is not up to date")
|
||||
|
||||
showLast100MessagesBeforeAndEqual(
|
||||
// set up field map to load the newest messages
|
||||
val fieldMap = getFieldMap(
|
||||
lookIntoFuture = false,
|
||||
includeLastKnown = true,
|
||||
setReadMarker = true,
|
||||
lastKnown = null
|
||||
)
|
||||
withNetworkParams.putSerializable(BundleKeys.KEY_FIELD_MAP, fieldMap)
|
||||
withNetworkParams.putString(BundleKeys.KEY_ROOM_TOKEN, conversationModel.token)
|
||||
|
||||
Log.d(TAG, "Starting online request for initial loading")
|
||||
val chatMessageEntities = sync(withNetworkParams)
|
||||
if (chatMessageEntities == null) {
|
||||
Log.e(TAG, "initial loading of messages failed")
|
||||
}
|
||||
|
||||
newestMessageId = chatDao.getNewestMessageId(internalConversationId)
|
||||
Log.d(TAG, "newestMessageId after sync: $newestMessageId")
|
||||
} else {
|
||||
Log.d(TAG, "Initial online request is skipped because offline messages are up to date")
|
||||
}
|
||||
|
||||
val chatBlock = getBlockOfMessage(newestMessageId.toInt())
|
||||
|
||||
val amountBetween = chatDao.getCountBetweenMessageIds(
|
||||
internalConversationId,
|
||||
chatDao.getNewestMessageId(internalConversationId)
|
||||
newestMessageId,
|
||||
chatBlock!!.oldestMessageId
|
||||
)
|
||||
|
||||
Log.d(TAG, "amount of messages between newestMessageId and oldest message of same ChatBlock:$amountBetween")
|
||||
val limit = if (amountBetween > DEFAULT_MESSAGES_LIMIT) {
|
||||
DEFAULT_MESSAGES_LIMIT
|
||||
} else {
|
||||
amountBetween
|
||||
}
|
||||
Log.d(TAG, "limit of messages to load for UI (max 100 to ensure performance is okay):$limit")
|
||||
|
||||
showMessagesBeforeAndEqual(
|
||||
internalConversationId,
|
||||
newestMessageId,
|
||||
limit
|
||||
)
|
||||
|
||||
// delay is a dirty workaround to make sure messages are added to adapter on initial load before dealing
|
||||
@ -175,10 +212,11 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
val loadFromServer = hasToLoadPreviousMessagesFromServer(beforeMessageId)
|
||||
|
||||
if (loadFromServer) {
|
||||
Log.d(TAG, "Starting online request for loadMoreMessages")
|
||||
sync(withNetworkParams)
|
||||
}
|
||||
|
||||
showLast100MessagesBefore(internalConversationId, beforeMessageId)
|
||||
showMessagesBefore(internalConversationId, beforeMessageId, DEFAULT_MESSAGES_LIMIT)
|
||||
updateUiForLastCommonRead()
|
||||
}
|
||||
|
||||
@ -205,6 +243,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
// sync database with server (This is a long blocking call because long polling (lookIntoFuture) is set)
|
||||
networkParams.putSerializable(BundleKeys.KEY_FIELD_MAP, fieldMap)
|
||||
|
||||
Log.d(TAG, "Starting online request for long polling")
|
||||
val resultsFromSync = sync(networkParams)
|
||||
if (!resultsFromSync.isNullOrEmpty()) {
|
||||
val chatMessages = resultsFromSync.map(ChatMessageEntity::asModel)
|
||||
@ -240,15 +279,15 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
loadFromServer = false
|
||||
} else {
|
||||
// we know that beforeMessageId and blockForMessage.oldestMessageId are in the same block.
|
||||
// As we want the last 100 entries before beforeMessageId, we calculate if these messages are 100
|
||||
// entries apart from each other
|
||||
// As we want the last DEFAULT_MESSAGES_LIMIT entries before beforeMessageId, we calculate if these
|
||||
// messages are DEFAULT_MESSAGES_LIMIT entries apart from each other
|
||||
|
||||
val amountBetween = chatDao.getCountBetweenMessageIds(
|
||||
internalConversationId,
|
||||
beforeMessageId,
|
||||
blockForMessage.oldestMessageId
|
||||
)
|
||||
loadFromServer = amountBetween < 100
|
||||
loadFromServer = amountBetween < DEFAULT_MESSAGES_LIMIT
|
||||
|
||||
Log.d(
|
||||
TAG,
|
||||
@ -263,7 +302,8 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
lookIntoFuture: Boolean,
|
||||
includeLastKnown: Boolean,
|
||||
setReadMarker: Boolean,
|
||||
lastKnown: Int?
|
||||
lastKnown: Int?,
|
||||
limit: Int = DEFAULT_MESSAGES_LIMIT
|
||||
): HashMap<String, Int> {
|
||||
val fieldMap = HashMap<String, Int>()
|
||||
|
||||
@ -278,7 +318,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
}
|
||||
|
||||
fieldMap["timeout"] = if (lookIntoFuture) 30 else 0
|
||||
fieldMap["limit"] = 100
|
||||
fieldMap["limit"] = limit
|
||||
fieldMap["lookIntoFuture"] = if (lookIntoFuture) 1 else 0
|
||||
fieldMap["setReadMarker"] = if (setReadMarker) 1 else 0
|
||||
|
||||
@ -294,12 +334,12 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
lookIntoFuture = false,
|
||||
includeLastKnown = true,
|
||||
setReadMarker = false,
|
||||
lastKnown = messageId.toInt()
|
||||
lastKnown = messageId.toInt(),
|
||||
limit = 1
|
||||
)
|
||||
bundle.putSerializable(BundleKeys.KEY_FIELD_MAP, fieldMap)
|
||||
|
||||
// Although only the single message will be returned, a server request will load 100 messages.
|
||||
// If this turns out to be confusion for debugging we could load set the limit to 1 for this request.
|
||||
Log.d(TAG, "Starting online request for single message (e.g. a reply)")
|
||||
sync(bundle)
|
||||
}
|
||||
return chatDao.getChatMessageForConversation(internalConversationId, messageId)
|
||||
@ -308,59 +348,70 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun getMessagesFromServer(bundle: Bundle): Pair<Int, List<ChatMessageJson>>? {
|
||||
Log.d(TAG, "An online request is made!!!!!!!!!!!!!!!!!!!!")
|
||||
val fieldMap = bundle.getSerializable(BundleKeys.KEY_FIELD_MAP) as HashMap<String, Int>
|
||||
|
||||
try {
|
||||
val result = network.pullChatMessages(credentials, urlForChatting, fieldMap)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
// .timeout(3, TimeUnit.SECONDS)
|
||||
.map { it ->
|
||||
when (it.code()) {
|
||||
HTTP_CODE_OK -> {
|
||||
Log.d(TAG, "getMessagesFromServer HTTP_CODE_OK")
|
||||
newXChatLastCommonRead = it.headers()["X-Chat-Last-Common-Read"]?.let {
|
||||
Integer.parseInt(it)
|
||||
var attempts = 1
|
||||
while (attempts < 5) {
|
||||
Log.d(TAG, "message limit: " + fieldMap["limit"])
|
||||
try {
|
||||
val result = network.pullChatMessages(credentials, urlForChatting, fieldMap)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.map { it ->
|
||||
when (it.code()) {
|
||||
HTTP_CODE_OK -> {
|
||||
Log.d(TAG, "getMessagesFromServer HTTP_CODE_OK")
|
||||
newXChatLastCommonRead = it.headers()["X-Chat-Last-Common-Read"]?.let {
|
||||
Integer.parseInt(it)
|
||||
}
|
||||
|
||||
return@map Pair(
|
||||
HTTP_CODE_OK,
|
||||
(it.body() as ChatOverall).ocs!!.data!!
|
||||
)
|
||||
}
|
||||
|
||||
return@map Pair(
|
||||
HTTP_CODE_OK,
|
||||
(it.body() as ChatOverall).ocs!!.data!!
|
||||
)
|
||||
}
|
||||
HTTP_CODE_NOT_MODIFIED -> {
|
||||
Log.d(TAG, "getMessagesFromServer HTTP_CODE_NOT_MODIFIED")
|
||||
|
||||
HTTP_CODE_NOT_MODIFIED -> {
|
||||
Log.d(TAG, "getMessagesFromServer HTTP_CODE_NOT_MODIFIED")
|
||||
return@map Pair(
|
||||
HTTP_CODE_NOT_MODIFIED,
|
||||
listOf<ChatMessageJson>()
|
||||
)
|
||||
}
|
||||
|
||||
return@map Pair(
|
||||
HTTP_CODE_NOT_MODIFIED,
|
||||
listOf<ChatMessageJson>()
|
||||
)
|
||||
}
|
||||
HTTP_CODE_PRECONDITION_FAILED -> {
|
||||
Log.d(TAG, "getMessagesFromServer HTTP_CODE_PRECONDITION_FAILED")
|
||||
|
||||
HTTP_CODE_PRECONDITION_FAILED -> {
|
||||
Log.d(TAG, "getMessagesFromServer HTTP_CODE_PRECONDITION_FAILED")
|
||||
return@map Pair(
|
||||
HTTP_CODE_PRECONDITION_FAILED,
|
||||
listOf<ChatMessageJson>()
|
||||
)
|
||||
}
|
||||
|
||||
return@map Pair(
|
||||
HTTP_CODE_PRECONDITION_FAILED,
|
||||
listOf<ChatMessageJson>()
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
return@map Pair(
|
||||
HTTP_CODE_PRECONDITION_FAILED,
|
||||
listOf<ChatMessageJson>()
|
||||
)
|
||||
else -> {
|
||||
return@map Pair(
|
||||
HTTP_CODE_PRECONDITION_FAILED,
|
||||
listOf<ChatMessageJson>()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
.blockingSingle()
|
||||
return result
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Something went wrong when pulling chat messages (attempt: $attempts)", e)
|
||||
attempts++
|
||||
|
||||
val newMessageLimit = when (attempts) {
|
||||
2 -> 50
|
||||
3 -> 10
|
||||
else -> 5
|
||||
}
|
||||
.blockingSingle()
|
||||
return result
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Something went wrong when pulling chat messages", e)
|
||||
fieldMap["limit"] = newMessageLimit
|
||||
}
|
||||
}
|
||||
Log.e(TAG, "All attempts to get messages from server failed")
|
||||
return null
|
||||
}
|
||||
|
||||
@ -370,7 +421,12 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
return null
|
||||
}
|
||||
|
||||
val result = getMessagesFromServer(bundle) ?: return listOf()
|
||||
val result = getMessagesFromServer(bundle)
|
||||
if (result == null) {
|
||||
Log.d(TAG, "No result from server")
|
||||
return null
|
||||
}
|
||||
|
||||
var chatMessagesFromSync: List<ChatMessageEntity>? = null
|
||||
|
||||
val fieldMap = bundle.getSerializable(BundleKeys.KEY_FIELD_MAP) as HashMap<String, Int>
|
||||
@ -471,7 +527,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
ChatMessage.SystemMessageType.CLEARED_CHAT -> {
|
||||
// for lookIntoFuture just deleting everything would be fine.
|
||||
// But lets say we did not open the chat for a while and in between it was cleared.
|
||||
// We just load the last 100 messages but this don't contain the system message.
|
||||
// We just load the last messages but this don't contain the system message.
|
||||
// We scroll up and load the system message. Deleting everything is not an option as we
|
||||
// would loose the messages that we want to keep. We only want to
|
||||
// delete the messages and chatBlocks older than the system message.
|
||||
@ -488,13 +544,12 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
* 304 is returned when oldest message of chat was queried or when long polling request returned with no
|
||||
* modification. hasHistory is only set to false, when 304 was returned for the the oldest message
|
||||
*/
|
||||
private fun getHasHistory(statusCode: Int, lookIntoFuture: Boolean): Boolean {
|
||||
return if (statusCode == HTTP_CODE_NOT_MODIFIED) {
|
||||
private fun getHasHistory(statusCode: Int, lookIntoFuture: Boolean): Boolean =
|
||||
if (statusCode == HTTP_CODE_NOT_MODIFIED) {
|
||||
lookIntoFuture
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getBlockOfMessage(queriedMessageId: Int?): ChatBlockEntity? {
|
||||
var blockContainingQueriedMessage: ChatBlockEntity? = null
|
||||
@ -563,7 +618,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun showLast100MessagesBeforeAndEqual(internalConversationId: String, messageId: Long) {
|
||||
private suspend fun showMessagesBeforeAndEqual(internalConversationId: String, messageId: Long, limit: Int) {
|
||||
suspend fun getMessagesBeforeAndEqual(
|
||||
messageId: Long,
|
||||
internalConversationId: String,
|
||||
@ -580,7 +635,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
val list = getMessagesBeforeAndEqual(
|
||||
messageId,
|
||||
internalConversationId,
|
||||
100
|
||||
limit
|
||||
)
|
||||
|
||||
if (list.isNotEmpty()) {
|
||||
@ -589,7 +644,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun showLast100MessagesBefore(internalConversationId: String, messageId: Long) {
|
||||
private suspend fun showMessagesBefore(internalConversationId: String, messageId: Long, limit: Int) {
|
||||
suspend fun getMessagesBefore(
|
||||
messageId: Long,
|
||||
internalConversationId: String,
|
||||
@ -606,7 +661,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
val list = getMessagesBefore(
|
||||
messageId,
|
||||
internalConversationId,
|
||||
100
|
||||
limit
|
||||
)
|
||||
|
||||
if (list.isNotEmpty()) {
|
||||
@ -638,5 +693,6 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
private const val HTTP_CODE_PRECONDITION_FAILED = 412
|
||||
private const val HALF_SECOND = 500L
|
||||
private const val DELAY_TO_ENSURE_MESSAGES_ARE_ADDED: Long = 100
|
||||
private const val DEFAULT_MESSAGES_LIMIT = 100
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user