Skip to content

Commit eb33b8c

Browse files
committed
Refactor: Make MessageReceiptManager functions suspend
The `MessageReceiptManager` is refactored to use `suspend` functions instead of launching new coroutines from a provided `CoroutineScope`. This simplifies the class by removing the need for an injected scope and improves testability. Key changes: - `markChannelsAsDelivered` and `markMessageAsDelivered` are now `suspend` functions. - The `CoroutineScope` dependency has been removed from `MessageReceiptManager` and its initialization in `ChatClient`. - `MessageDeliveredPlugin` is updated to use `onSuccessSuspend` to call the new suspend functions. - `ChatNotificationsImpl` now launches a coroutine to call the suspend function `markMessageAsDelivered`. - Tests are updated to use `verifyBlocking` for testing suspend functions and to provide the necessary `CoroutineScope` where required.
1 parent 8f40115 commit eb33b8c

File tree

7 files changed

+25
-30
lines changed

7 files changed

+25
-30
lines changed

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/ChatClient.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,6 @@ internal constructor(
335335
private var _repositoryFacade: RepositoryFacade? = null
336336

337337
internal val messageReceiptManager = MessageReceiptManager(
338-
scope = userScope,
339338
now = now,
340339
getCurrentUser = ::getCurrentUser,
341340
channelRepository = repositoryFacade,

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/notifications/ChatNotifications.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ internal class ChatNotificationsImpl(
114114
id = pushMessage.messageId,
115115
cid = "${pushMessage.channelType}:${pushMessage.channelId}",
116116
)
117-
chatClient.messageReceiptManager.markMessageAsDelivered(message)
117+
scope.launch { chatClient.messageReceiptManager.markMessageAsDelivered(message) }
118118

119119
if (notificationConfig.shouldShowNotificationOnPush() && !handler.onPushMessage(pushMessage)) {
120120
handlePushMessage(pushMessage)

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/plugin/MessageDeliveredPlugin.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import io.getstream.chat.android.client.receipts.MessageReceiptManager
2424
import io.getstream.chat.android.models.Channel
2525
import io.getstream.chat.android.models.User
2626
import io.getstream.result.Result
27+
import io.getstream.result.onSuccessSuspend
2728

2829
/**
2930
* A plugin that marks messages as delivered when channels are queried.
@@ -34,7 +35,7 @@ internal class MessageDeliveredPlugin(
3435
) : Plugin {
3536

3637
override suspend fun onQueryChannelsResult(result: Result<List<Channel>>, request: QueryChannelsRequest) {
37-
result.onSuccess { channels ->
38+
result.onSuccessSuspend { channels ->
3839
messageReceiptManager.markChannelsAsDelivered(channels)
3940
}
4041
}
@@ -45,7 +46,7 @@ internal class MessageDeliveredPlugin(
4546
channelId: String,
4647
request: QueryChannelRequest,
4748
) {
48-
result.onSuccess { channel ->
49+
result.onSuccessSuspend { channel ->
4950
if (request.pagination() == null) { // only mark as delivered on initial load
5051
messageReceiptManager.markChannelsAsDelivered(channels = listOf(channel))
5152
}

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/receipts/MessageReceiptManager.kt

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,13 @@ import io.getstream.chat.android.models.Message
3131
import io.getstream.chat.android.models.MessageType
3232
import io.getstream.chat.android.models.User
3333
import io.getstream.log.taggedLogger
34-
import kotlinx.coroutines.CoroutineScope
35-
import kotlinx.coroutines.launch
3634
import java.util.Date
3735

3836
/**
3937
* Manages message delivery receipts: creating and storing them in the repository
4038
* for later reporting to the server.
4139
*/
4240
internal class MessageReceiptManager(
43-
private val scope: CoroutineScope,
4441
private val now: () -> Date,
4542
private val getCurrentUser: () -> User?,
4643
private val channelRepository: ChannelRepository,
@@ -64,7 +61,7 @@ internal class MessageReceiptManager(
6461
* - Is not yet marked as read by the current user
6562
* - Is not yet marked as delivered by the current user
6663
*/
67-
fun markChannelsAsDelivered(channels: List<Channel>) {
64+
suspend fun markChannelsAsDelivered(channels: List<Channel>) {
6865
val currentUser = getCurrentUser() ?: run {
6966
logger.w { "[markChannelsAsDelivered] Current user is null" }
7067
return
@@ -86,23 +83,21 @@ internal class MessageReceiptManager(
8683
*
8784
* @see [markChannelsAsDelivered] for the conditions to mark a message as delivered.
8885
*/
89-
fun markMessageAsDelivered(message: Message) {
86+
suspend fun markMessageAsDelivered(message: Message) {
9087
val currentUser = getCurrentUser() ?: run {
9188
logger.w { "[markMessageAsDelivered] Current user is null" }
9289
return
9390
}
9491

9592
if (!currentUser.isDeliveryReceiptsEnabled) return
9693

97-
scope.launch {
98-
val channel = getChannel(message.cid) ?: run {
99-
logger.w { "[markMessageAsDelivered] Channel ${message.cid} not found" }
100-
return@launch
101-
}
94+
val channel = getChannel(message.cid) ?: run {
95+
logger.w { "[markMessageAsDelivered] Channel ${message.cid} not found" }
96+
return
97+
}
10298

103-
if (canMarkMessageAsDelivered(currentUser, channel, message)) {
104-
markMessagesAsDelivered(messages = listOf(message))
105-
}
99+
if (canMarkMessageAsDelivered(currentUser, channel, message)) {
100+
markMessagesAsDelivered(messages = listOf(message))
106101
}
107102
}
108103

@@ -115,20 +110,18 @@ internal class MessageReceiptManager(
115110
.await().getOrNull()
116111
}
117112

118-
private fun markMessagesAsDelivered(messages: List<Message>) {
113+
private suspend fun markMessagesAsDelivered(messages: List<Message>) {
119114
if (messages.isEmpty()) {
120115
logger.w { "[markMessagesAsDelivered] No receipts to send" }
121116
return
122117
}
123118

124119
logger.d { "[markMessagesAsDelivered] Processing delivery receipts for ${messages.size} messages…" }
125120

126-
scope.launch {
127-
val receipts = messages.map { message -> message.toDeliveryReceipt() }
128-
messageReceiptRepository.upsertMessageReceipts(receipts)
121+
val receipts = messages.map { message -> message.toDeliveryReceipt() }
122+
messageReceiptRepository.upsertMessageReceipts(receipts)
129123

130-
logger.d { "[markMessagesAsDelivered] ${messages.size} delivery receipts upserted" }
131-
}
124+
logger.d { "[markMessagesAsDelivered] ${messages.size} delivery receipts upserted" }
132125
}
133126

134127
private fun canMarkMessageAsDelivered(

stream-chat-android-client/src/test/java/io/getstream/chat/android/client/notifications/ChatNotificationsImplTest.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,16 @@ import io.getstream.chat.android.client.randomPushMessage
2929
import io.getstream.chat.android.client.receipts.MessageReceiptManager
3030
import io.getstream.chat.android.models.Message
3131
import io.getstream.chat.android.models.PushMessage
32+
import kotlinx.coroutines.CoroutineScope
33+
import kotlinx.coroutines.test.UnconfinedTestDispatcher
3234
import org.junit.Test
3335
import org.junit.jupiter.api.Assertions.assertNotNull
3436
import org.junit.jupiter.api.Assertions.assertNull
3537
import org.junit.runner.RunWith
3638
import org.mockito.kotlin.doReturn
3739
import org.mockito.kotlin.mock
3840
import org.mockito.kotlin.verify
41+
import org.mockito.kotlin.verifyBlocking
3942
import org.mockito.kotlin.whenever
4043
import org.robolectric.annotation.Config
4144

@@ -130,7 +133,7 @@ internal class ChatNotificationsImplTest {
130133
}
131134

132135
fun verifyMarkMessageAsDeliveredCalled(message: Message) {
133-
verify(mockMessageReceiptManager).markMessageAsDelivered(message)
136+
verifyBlocking(mockMessageReceiptManager) { markMessageAsDelivered(message) }
134137
}
135138

136139
fun get(): ChatNotificationsImpl {
@@ -141,7 +144,7 @@ internal class ChatNotificationsImplTest {
141144
handler = mockNotificationHandler,
142145
notificationConfig = notificationConfig,
143146
context = context,
144-
scope = mock(),
147+
scope = CoroutineScope(UnconfinedTestDispatcher()),
145148
chatClientProvider = { mockChatClient },
146149
)
147150
}

stream-chat-android-client/src/test/java/io/getstream/chat/android/client/plugin/MessageDeliveredPluginTest.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import org.mockito.kotlin.doReturn
2727
import org.mockito.kotlin.mock
2828
import org.mockito.kotlin.never
2929
import org.mockito.kotlin.times
30-
import org.mockito.kotlin.verify
30+
import org.mockito.kotlin.verifyBlocking
3131
import org.mockito.verification.VerificationMode
3232

3333
internal class MessageDeliveredPluginTest {
@@ -109,7 +109,9 @@ internal class MessageDeliveredPluginTest {
109109
mode: VerificationMode = times(1),
110110
channels: List<Channel>? = null,
111111
) {
112-
verify(mockMessageReceiptManager, mode).markChannelsAsDelivered(channels ?: any())
112+
verifyBlocking(mockMessageReceiptManager, mode) {
113+
markChannelsAsDelivered(channels ?: any())
114+
}
113115
}
114116

115117
fun get() = MessageDeliveredPlugin(

stream-chat-android-client/src/test/java/io/getstream/chat/android/client/receipts/MessageReceiptManagerTest.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ import io.getstream.chat.android.randomMessage
3030
import io.getstream.chat.android.randomUser
3131
import io.getstream.chat.android.test.asCall
3232
import io.getstream.result.Error
33-
import kotlinx.coroutines.CoroutineScope
34-
import kotlinx.coroutines.test.UnconfinedTestDispatcher
3533
import kotlinx.coroutines.test.runTest
3634
import org.junit.Test
3735
import org.mockito.kotlin.any
@@ -345,7 +343,6 @@ internal class MessageReceiptManagerTest {
345343
}
346344

347345
fun get() = MessageReceiptManager(
348-
scope = CoroutineScope(UnconfinedTestDispatcher()),
349346
now = { Now },
350347
getCurrentUser = getCurrentUser,
351348
channelRepository = mockChannelRepository,

0 commit comments

Comments
 (0)