Skip to content

Commit 97d4e63

Browse files
committed
Sync on push : call startSync/stopSync
1 parent 6b8dba6 commit 97d4e63

File tree

2 files changed

+89
-16
lines changed

2 files changed

+89
-16
lines changed

libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/OnNotifiableEventReceived.kt

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ package io.element.android.libraries.push.impl.push
1818

1919
import com.squareup.anvil.annotations.ContributesBinding
2020
import io.element.android.libraries.di.AppScope
21-
import io.element.android.libraries.featureflag.api.FeatureFlagService
22-
import io.element.android.libraries.featureflag.api.FeatureFlags
23-
import io.element.android.libraries.matrix.api.MatrixClientProvider
2421
import io.element.android.libraries.push.impl.notifications.DefaultNotificationDrawerManager
2522
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
2623
import kotlinx.coroutines.CoroutineScope
@@ -35,23 +32,12 @@ interface OnNotifiableEventReceived {
3532
class DefaultOnNotifiableEventReceived @Inject constructor(
3633
private val defaultNotificationDrawerManager: DefaultNotificationDrawerManager,
3734
private val coroutineScope: CoroutineScope,
38-
private val matrixClientProvider: MatrixClientProvider,
39-
private val featureFlagService: FeatureFlagService,
35+
private val syncOnNotifiableEvent: SyncOnNotifiableEvent,
4036
) : OnNotifiableEventReceived {
4137
override fun onNotifiableEventReceived(notifiableEvent: NotifiableEvent) {
4238
coroutineScope.launch {
43-
subscribeToRoomIfNeeded(notifiableEvent)
39+
launch { syncOnNotifiableEvent(notifiableEvent) }
4440
defaultNotificationDrawerManager.onNotifiableEventReceived(notifiableEvent)
4541
}
4642
}
47-
48-
private fun CoroutineScope.subscribeToRoomIfNeeded(notifiableEvent: NotifiableEvent) = launch {
49-
if (!featureFlagService.isFeatureEnabled(FeatureFlags.SyncOnPush)) {
50-
return@launch
51-
}
52-
val client = matrixClientProvider.getOrRestore(notifiableEvent.sessionId).getOrNull() ?: return@launch
53-
client.getRoom(notifiableEvent.roomId)?.use { room ->
54-
room.subscribeToSync()
55-
}
56-
}
5743
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright (c) 2024 New Vector Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.element.android.libraries.push.impl.push
18+
19+
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
20+
import io.element.android.libraries.featureflag.api.FeatureFlagService
21+
import io.element.android.libraries.featureflag.api.FeatureFlags
22+
import io.element.android.libraries.matrix.api.MatrixClientProvider
23+
import io.element.android.libraries.matrix.api.core.EventId
24+
import io.element.android.libraries.matrix.api.room.MatrixRoom
25+
import io.element.android.libraries.matrix.api.sync.SyncService
26+
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
27+
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
28+
import io.element.android.services.appnavstate.api.AppForegroundStateService
29+
import kotlinx.coroutines.flow.first
30+
import kotlinx.coroutines.withContext
31+
import kotlinx.coroutines.withTimeoutOrNull
32+
import java.util.concurrent.atomic.AtomicInteger
33+
import javax.inject.Inject
34+
import kotlin.time.Duration
35+
import kotlin.time.Duration.Companion.seconds
36+
37+
class SyncOnNotifiableEvent @Inject constructor(
38+
private val matrixClientProvider: MatrixClientProvider,
39+
private val featureFlagService: FeatureFlagService,
40+
private val appForegroundStateService: AppForegroundStateService,
41+
private val dispatchers: CoroutineDispatchers,
42+
) {
43+
private var syncCounter = AtomicInteger(0)
44+
45+
suspend operator fun invoke(notifiableEvent: NotifiableEvent) = withContext(dispatchers.io) {
46+
if (!featureFlagService.isFeatureEnabled(FeatureFlags.SyncOnPush)) {
47+
return@withContext
48+
}
49+
val client = matrixClientProvider.getOrRestore(notifiableEvent.sessionId).getOrNull() ?: return@withContext
50+
client.getRoom(notifiableEvent.roomId)?.use { room ->
51+
room.subscribeToSync()
52+
53+
// If the app is in foreground, sync is already running, so just add the subscription.
54+
if (!appForegroundStateService.isInForeground.value) {
55+
val syncService = client.syncService()
56+
syncService.startSyncIfNeeded()
57+
room.waitsUntilEventIsKnown(eventId = notifiableEvent.eventId, timeout = 10.seconds)
58+
syncService.stopSyncIfNeeded()
59+
}
60+
}
61+
}
62+
63+
private suspend fun MatrixRoom.waitsUntilEventIsKnown(eventId: EventId, timeout: Duration) {
64+
withTimeoutOrNull(timeout) {
65+
liveTimeline.timelineItems.first { timelineItems ->
66+
timelineItems.any { timelineItem ->
67+
when (timelineItem) {
68+
is MatrixTimelineItem.Event -> timelineItem.eventId == eventId
69+
else -> false
70+
}
71+
}
72+
}
73+
}
74+
}
75+
76+
private suspend fun SyncService.startSyncIfNeeded() {
77+
if (syncCounter.getAndIncrement() == 0) {
78+
startSync()
79+
}
80+
}
81+
82+
private suspend fun SyncService.stopSyncIfNeeded() {
83+
if (syncCounter.decrementAndGet() == 0 && !appForegroundStateService.isInForeground.value) {
84+
stopSync()
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)