From d3e4e97c6f95ee2a2dc11cc7ff48497b0f22baf8 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Tue, 5 Sep 2023 10:29:51 +0300 Subject: [PATCH] Fix tracker operations parallelism --- .../kotatsu/tracker/domain/Tracker.kt | 13 +++-- .../tracker/domain/model/MangaUpdates.kt | 5 +- .../kotatsu/tracker/work/TrackWorker.kt | 52 +++++++++++++------ 3 files changed, 49 insertions(+), 21 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/Tracker.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/Tracker.kt index 5bdf1a686..73dc18841 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/Tracker.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/Tracker.kt @@ -110,21 +110,26 @@ class Tracker @Inject constructor( private fun compare(track: MangaTracking, manga: Manga, branch: String?): MangaUpdates.Success { if (track.isEmpty()) { // first check or manga was empty on last check - return MangaUpdates.Success(manga, emptyList(), isValid = false) + return MangaUpdates.Success(manga, emptyList(), isValid = false, channelId = null) } val chapters = requireNotNull(manga.getChapters(branch)) val newChapters = chapters.takeLastWhile { x -> x.id != track.lastChapterId } return when { newChapters.isEmpty() -> { - MangaUpdates.Success(manga, emptyList(), isValid = chapters.lastOrNull()?.id == track.lastChapterId) + MangaUpdates.Success( + manga = manga, + newChapters = emptyList(), + isValid = chapters.lastOrNull()?.id == track.lastChapterId, + channelId = null + ) } newChapters.size == chapters.size -> { - MangaUpdates.Success(manga, emptyList(), isValid = false) + MangaUpdates.Success(manga, emptyList(), isValid = false, channelId = null) } else -> { - MangaUpdates.Success(manga, newChapters, isValid = true) + MangaUpdates.Success(manga, newChapters, isValid = true, channelId = null) } } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/model/MangaUpdates.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/model/MangaUpdates.kt index b1c2da4a5..6dc13dd60 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/model/MangaUpdates.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/model/MangaUpdates.kt @@ -8,16 +8,17 @@ sealed interface MangaUpdates { val manga: Manga - class Success( + data class Success( override val manga: Manga, val newChapters: List, val isValid: Boolean, + val channelId: String?, ) : MangaUpdates { fun isNotEmpty() = newChapters.isNotEmpty() } - class Failure( + data class Failure( override val manga: Manga, val error: Throwable?, ) : MangaUpdates { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt index 06aa47101..08511fc30 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt @@ -39,6 +39,7 @@ import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.channelFlow import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.toList import kotlinx.coroutines.launch import kotlinx.coroutines.runInterruptible @@ -148,19 +149,9 @@ class TrackWorker @AssistedInject constructor( send( runCatchingCancellable { tracker.fetchUpdates(track, commit = true) + .copy(channelId = channelId) }.onFailure { e -> - if (e is CloudFlareProtectedException) { - CaptchaNotifier(applicationContext).notify(e) - } logger.log("checkUpdatesAsync", e) - }.onSuccess { updates -> - if (updates.isValid && updates.isNotEmpty()) { - showNotification( - manga = updates.manga, - channelId = channelId, - newChapters = updates.newChapters, - ) - } }.getOrElse { error -> MangaUpdates.Failure( manga = track.manga, @@ -171,10 +162,33 @@ class TrackWorker @AssistedInject constructor( } } } + }.onEach { + when (it) { + is MangaUpdates.Failure -> { + val e = it.error + if (e is CloudFlareProtectedException) { + CaptchaNotifier(applicationContext).notify(e) + } + } + + is MangaUpdates.Success -> { + if (it.isValid && it.isNotEmpty()) { + showNotification( + manga = it.manga, + channelId = it.channelId, + newChapters = it.newChapters, + ) + } + } + } }.toList(ArrayList(tracks.size)) } - private suspend fun showNotification(manga: Manga, channelId: String?, newChapters: List) { + private suspend fun showNotification( + manga: Manga, + channelId: String?, + newChapters: List, + ) { if (newChapters.isEmpty() || channelId == null || !applicationContext.checkNotificationPermission()) { return } @@ -239,7 +253,10 @@ class TrackWorker @AssistedInject constructor( override suspend fun getForegroundInfo(): ForegroundInfo { val title = applicationContext.getString(R.string.check_for_new_chapters) - val channel = NotificationChannelCompat.Builder(WORKER_CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_LOW) + val channel = NotificationChannelCompat.Builder( + WORKER_CHANNEL_ID, + NotificationManagerCompat.IMPORTANCE_LOW + ) .setName(title) .setShowBadge(false) .setVibrationEnabled(false) @@ -260,7 +277,11 @@ class TrackWorker @AssistedInject constructor( .setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_DEFERRED) .build() return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - ForegroundInfo(WORKER_NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC) + ForegroundInfo( + WORKER_NOTIFICATION_ID, + notification, + ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC + ) } else { ForegroundInfo(WORKER_NOTIFICATION_ID, notification) } @@ -320,7 +341,8 @@ class TrackWorker @AssistedInject constructor( } fun startNow() { - val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build() + val constraints = + Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build() val request = OneTimeWorkRequestBuilder() .setConstraints(constraints) .addTag(TAG_ONESHOT)