@@ -3,74 +3,76 @@ package suwayomi.tachidesk.manga.impl.update
3
3
import kotlinx.coroutines.CancellationException
4
4
import kotlinx.coroutines.CoroutineScope
5
5
import kotlinx.coroutines.Dispatchers
6
- import kotlinx.coroutines.Job
7
6
import kotlinx.coroutines.SupervisorJob
8
- import kotlinx.coroutines.cancel
7
+ import kotlinx.coroutines.cancelChildren
9
8
import kotlinx.coroutines.channels.Channel
10
9
import kotlinx.coroutines.flow.MutableStateFlow
11
- import kotlinx.coroutines.flow.StateFlow
10
+ import kotlinx.coroutines.flow.asStateFlow
11
+ import kotlinx.coroutines.flow.catch
12
+ import kotlinx.coroutines.flow.consumeAsFlow
13
+ import kotlinx.coroutines.flow.launchIn
14
+ import kotlinx.coroutines.flow.onEach
15
+ import kotlinx.coroutines.flow.update
12
16
import kotlinx.coroutines.launch
13
17
import mu.KotlinLogging
14
18
import suwayomi.tachidesk.manga.impl.Chapter
15
19
import suwayomi.tachidesk.manga.model.dataclass.MangaDataClass
20
+ import java.util.concurrent.ConcurrentHashMap
16
21
17
22
class Updater : IUpdater {
18
23
private val logger = KotlinLogging .logger {}
19
24
private val scope = CoroutineScope (SupervisorJob () + Dispatchers .Default )
20
25
21
- private var tracker = mutableMapOf<String , UpdateJob >()
22
- private var updateChannel = Channel <UpdateJob >()
23
- private val statusChannel = MutableStateFlow (UpdateStatus ())
24
- private var updateJob: Job ? = null
26
+ private val _status = MutableStateFlow (UpdateStatus ())
27
+ override val status = _status .asStateFlow()
25
28
26
- init {
27
- updateJob = createUpdateJob()
28
- }
29
+ private val tracker = ConcurrentHashMap <Int , UpdateJob >()
30
+ private var updateChannel = createUpdateChannel()
29
31
30
- private fun createUpdateJob (): Job {
31
- return scope.launch {
32
- while (true ) {
33
- val job = updateChannel.receive()
34
- process(job)
35
- statusChannel.value = UpdateStatus (tracker.values.toList(), ! updateChannel.isEmpty)
32
+ private fun createUpdateChannel (): Channel <UpdateJob > {
33
+ val channel = Channel <UpdateJob >(Channel .UNLIMITED )
34
+ channel.consumeAsFlow()
35
+ .onEach { job ->
36
+ _status .value = UpdateStatus (
37
+ process(job),
38
+ tracker.any { (_, job) ->
39
+ job.status == JobStatus .PENDING || job.status == JobStatus .RUNNING
40
+ }
41
+ )
36
42
}
37
- }
43
+ .catch { logger.error(it) { " Error during updates" } }
44
+ .launchIn(scope)
45
+ return channel
38
46
}
39
47
40
- private suspend fun process (job : UpdateJob ) {
41
- job.status = JobStatus .RUNNING
42
- tracker[" ${job.manga.id} " ] = job
43
- statusChannel.value = UpdateStatus (tracker.values.toList(), true )
44
- try {
48
+ private suspend fun process (job : UpdateJob ): List <UpdateJob > {
49
+ tracker[job.manga.id] = job.copy(status = JobStatus .RUNNING )
50
+ _status .update { UpdateStatus (tracker.values.toList(), true ) }
51
+ tracker[job.manga.id] = try {
45
52
logger.info { " Updating ${job.manga.title} " }
46
53
Chapter .getChapterList(job.manga.id, true )
47
- job.status = JobStatus .COMPLETE
54
+ job.copy( status = JobStatus .COMPLETE )
48
55
} catch (e: Exception ) {
49
56
if (e is CancellationException ) throw e
50
57
logger.error(e) { " Error while updating ${job.manga.title} " }
51
- job.status = JobStatus .FAILED
58
+ job.copy( status = JobStatus .FAILED )
52
59
}
53
- tracker[ " ${job.manga.id} " ] = job
60
+ return tracker.values.toList()
54
61
}
55
62
56
63
override fun addMangaToQueue (manga : MangaDataClass ) {
57
64
scope.launch {
58
65
updateChannel.send(UpdateJob (manga))
59
66
}
60
- tracker[" ${manga.id} " ] = UpdateJob (manga)
61
- statusChannel.value = UpdateStatus (tracker.values.toList(), true )
62
- }
63
-
64
- override fun getStatus (): StateFlow <UpdateStatus > {
65
- return statusChannel
67
+ tracker[manga.id] = UpdateJob (manga)
68
+ _status .update { UpdateStatus (tracker.values.toList(), true ) }
66
69
}
67
70
68
- override suspend fun reset () {
71
+ override fun reset () {
72
+ scope.coroutineContext.cancelChildren()
69
73
tracker.clear()
74
+ _status .update { UpdateStatus () }
70
75
updateChannel.cancel()
71
- statusChannel.value = UpdateStatus ()
72
- updateJob?.cancel(" Reset" )
73
- updateChannel = Channel ()
74
- updateJob = createUpdateJob()
76
+ updateChannel = createUpdateChannel()
75
77
}
76
78
}
0 commit comments