From 75e992281e2c4054efd7d4721a9a725316a300ae Mon Sep 17 00:00:00 2001 From: Kevin Boulongne Date: Thu, 7 Mar 2024 10:13:19 +0100 Subject: [PATCH 1/2] Small optimisation of duration in RefreshThreads algo --- .../mail/data/cache/mailboxContent/RefreshController.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/infomaniak/mail/data/cache/mailboxContent/RefreshController.kt b/app/src/main/java/com/infomaniak/mail/data/cache/mailboxContent/RefreshController.kt index 9b83f5c896..ca69944e2f 100644 --- a/app/src/main/java/com/infomaniak/mail/data/cache/mailboxContent/RefreshController.kt +++ b/app/src/main/java/com/infomaniak/mail/data/cache/mailboxContent/RefreshController.kt @@ -52,6 +52,7 @@ import okhttp3.OkHttpClient import java.util.Date import javax.inject.Inject import javax.inject.Singleton +import kotlin.math.abs import kotlin.math.max @Singleton @@ -516,6 +517,8 @@ class RefreshController @Inject constructor( cursor: String, ): Set { + val startTime = System.currentTimeMillis() + val logMessage = "Added: ${uids.count()}" SentryLog.d("API", "$logMessage | ${folder.name}") @@ -525,9 +528,7 @@ class RefreshController @Inject constructor( val impactedThreads = mutableSetOf() - val before = System.currentTimeMillis() val apiResponse = ApiRepository.getMessagesByUids(mailbox.uuid, folder.id, uids, okHttpClient) - val after = System.currentTimeMillis() if (!apiResponse.isSuccess()) apiResponse.throwErrorAsException() scope.ensureActive() @@ -558,7 +559,8 @@ class RefreshController @Inject constructor( * So we want to be sure that we don't write twice in less than 500 ms. * Appreciable side effect: it will also reduce the stress on the API. */ - val delay = Utils.MAX_DELAY_BETWEEN_API_CALLS - (after - before) + val duration = abs(System.currentTimeMillis() - startTime) + val delay = Utils.MAX_DELAY_BETWEEN_API_CALLS - duration if (delay > 0L) { delay(delay) scope.ensureActive() From 30b03875ffa1edeee08bb12f573a0959e6260b1b Mon Sep 17 00:00:00 2001 From: Kevin Boulongne Date: Thu, 14 Mar 2024 14:53:43 +0100 Subject: [PATCH 2/2] Move delay handling to its own Manager --- .../mailboxContent/DelayApiCallManager.kt | 65 +++++++++++++++++++ .../cache/mailboxContent/RefreshController.kt | 19 +----- .../java/com/infomaniak/mail/utils/Utils.kt | 1 - 3 files changed, 67 insertions(+), 18 deletions(-) create mode 100644 app/src/main/java/com/infomaniak/mail/data/cache/mailboxContent/DelayApiCallManager.kt diff --git a/app/src/main/java/com/infomaniak/mail/data/cache/mailboxContent/DelayApiCallManager.kt b/app/src/main/java/com/infomaniak/mail/data/cache/mailboxContent/DelayApiCallManager.kt new file mode 100644 index 0000000000..0a6bb9236e --- /dev/null +++ b/app/src/main/java/com/infomaniak/mail/data/cache/mailboxContent/DelayApiCallManager.kt @@ -0,0 +1,65 @@ +/* + * Infomaniak Mail - Android + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.infomaniak.mail.data.cache.mailboxContent + +import com.infomaniak.lib.core.models.ApiResponse +import com.infomaniak.mail.data.api.ApiRepository +import com.infomaniak.mail.data.models.getMessages.GetMessagesByUidsResult +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.ensureActive +import okhttp3.OkHttpClient +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.math.abs + +@Singleton +class DelayApiCallManager @Inject constructor() { + + private var previousTime = 0L + + /** + * Realm really doesn't like to be written on too frequently. + * So we want to be sure that we don't write twice in less than 500 ms. + * Appreciable side effect: it will also reduce the stress on the API. + */ + suspend fun getMessagesByUids( + scope: CoroutineScope, + mailboxUuid: String, + folderId: String, + uids: List, + okHttpClient: OkHttpClient?, + ): ApiResponse { + + val duration = abs(System.currentTimeMillis() - previousTime) + val delay = MAX_DELAY_BETWEEN_API_CALLS - duration + + if (delay > 0L) { + delay(delay) + scope.ensureActive() + } + + previousTime = System.currentTimeMillis() + + return ApiRepository.getMessagesByUids(mailboxUuid, folderId, uids, okHttpClient) + } + + companion object { + private const val MAX_DELAY_BETWEEN_API_CALLS = 500L + } +} diff --git a/app/src/main/java/com/infomaniak/mail/data/cache/mailboxContent/RefreshController.kt b/app/src/main/java/com/infomaniak/mail/data/cache/mailboxContent/RefreshController.kt index ca69944e2f..397f98d14d 100644 --- a/app/src/main/java/com/infomaniak/mail/data/cache/mailboxContent/RefreshController.kt +++ b/app/src/main/java/com/infomaniak/mail/data/cache/mailboxContent/RefreshController.kt @@ -52,13 +52,13 @@ import okhttp3.OkHttpClient import java.util.Date import javax.inject.Inject import javax.inject.Singleton -import kotlin.math.abs import kotlin.math.max @Singleton class RefreshController @Inject constructor( private val localSettings: LocalSettings, private val mailboxController: MailboxController, + private val delayApiCallManager: DelayApiCallManager, ) { private var refreshThreadsJob: Job? = null @@ -517,8 +517,6 @@ class RefreshController @Inject constructor( cursor: String, ): Set { - val startTime = System.currentTimeMillis() - val logMessage = "Added: ${uids.count()}" SentryLog.d("API", "$logMessage | ${folder.name}") @@ -528,7 +526,7 @@ class RefreshController @Inject constructor( val impactedThreads = mutableSetOf() - val apiResponse = ApiRepository.getMessagesByUids(mailbox.uuid, folder.id, uids, okHttpClient) + val apiResponse = delayApiCallManager.getMessagesByUids(scope, mailbox.uuid, folder.id, uids, okHttpClient) if (!apiResponse.isSuccess()) apiResponse.throwErrorAsException() scope.ensureActive() @@ -553,19 +551,6 @@ class RefreshController @Inject constructor( impactedThreads += allImpactedThreads.filter { it.folderId == folder.id } } } - - /** - * Realm really doesn't like to be written on too frequently. - * So we want to be sure that we don't write twice in less than 500 ms. - * Appreciable side effect: it will also reduce the stress on the API. - */ - val duration = abs(System.currentTimeMillis() - startTime) - val delay = Utils.MAX_DELAY_BETWEEN_API_CALLS - duration - if (delay > 0L) { - delay(delay) - scope.ensureActive() - } - } return impactedThreads diff --git a/app/src/main/java/com/infomaniak/mail/utils/Utils.kt b/app/src/main/java/com/infomaniak/mail/utils/Utils.kt index 3c99c75d62..d010ffbf32 100644 --- a/app/src/main/java/com/infomaniak/mail/utils/Utils.kt +++ b/app/src/main/java/com/infomaniak/mail/utils/Utils.kt @@ -38,7 +38,6 @@ object Utils { const val NUMBER_OF_OLD_MESSAGES_TO_FETCH = 500 /** Beware: the API refuses a PAGE_SIZE bigger than 200. */ const val PAGE_SIZE: Int = 50 - const val MAX_DELAY_BETWEEN_API_CALLS = 500L const val DELAY_BEFORE_FETCHING_ACTIVITIES_AGAIN = 500L const val TAG_SEPARATOR = " "