Skip to content

Commit c663cf9

Browse files
feat: fetch other user's protocols from remote when resolving 1:1 conversations (#2405) (#2418)
Co-authored-by: Vitor Hugo Schwaab <[email protected]>
1 parent 290c358 commit c663cf9

18 files changed

+252
-57
lines changed

logic/src/commonMain/kotlin/com/wire/kalium/logic/data/user/UserRepository.kt

-1
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,6 @@ internal class UserDataSource internal constructor(
228228

229229
override suspend fun fetchAllOtherUsers(): Either<CoreFailure, Unit> {
230230
val ids = userDAO.allOtherUsersId().map(UserIDEntity::toModel).toSet()
231-
232231
return fetchUsersByIds(ids)
233232
}
234233

logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt

+4-4
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,8 @@ import com.wire.kalium.logic.feature.user.SyncSelfUserUseCase
309309
import com.wire.kalium.logic.feature.user.SyncSelfUserUseCaseImpl
310310
import com.wire.kalium.logic.feature.user.UpdateSupportedProtocolsAndResolveOneOnOnesUseCase
311311
import com.wire.kalium.logic.feature.user.UpdateSupportedProtocolsAndResolveOneOnOnesUseCaseImpl
312-
import com.wire.kalium.logic.feature.user.UpdateSupportedProtocolsUseCase
313-
import com.wire.kalium.logic.feature.user.UpdateSupportedProtocolsUseCaseImpl
312+
import com.wire.kalium.logic.feature.user.UpdateSelfUserSupportedProtocolsUseCase
313+
import com.wire.kalium.logic.feature.user.UpdateSelfUserSupportedProtocolsUseCaseImpl
314314
import com.wire.kalium.logic.feature.user.UserScope
315315
import com.wire.kalium.logic.feature.user.e2ei.MarkNotifyForRevokedCertificateAsNotifiedUseCase
316316
import com.wire.kalium.logic.feature.user.e2ei.MarkNotifyForRevokedCertificateAsNotifiedUseCaseImpl
@@ -967,8 +967,8 @@ class UserSessionScope internal constructor(
967967
incrementalSyncRepository
968968
)
969969

970-
private val updateSupportedProtocols: UpdateSupportedProtocolsUseCase
971-
get() = UpdateSupportedProtocolsUseCaseImpl(
970+
private val updateSupportedProtocols: UpdateSelfUserSupportedProtocolsUseCase
971+
get() = UpdateSelfUserSupportedProtocolsUseCaseImpl(
972972
clientRepository,
973973
userRepository,
974974
userConfigRepository,

logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/connection/AcceptConnectionRequestUseCase.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ internal class AcceptConnectionRequestUseCaseImpl(
6262
)
6363
}.flatMap {
6464
oneOnOneResolver.resolveOneOnOneConversationWithUserId(
65-
connection.qualifiedToId
65+
userId = connection.qualifiedToId,
66+
invalidateCurrentKnownProtocols = true
6667
).map { }
6768
}.flatMap {
6869
newGroupConversationSystemMessagesCreator.conversationStartedUnverifiedWarning(

logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/GetOrCreateOneToOneConversationUseCase.kt

+4-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ internal class GetOrCreateOneToOneConversationUseCaseImpl(
6969
private suspend fun resolveOneOnOneConversationWithUser(otherUserId: UserId): Either<CoreFailure, Conversation> =
7070
(userRepository.getKnownUser(otherUserId).first()?.let { otherUser ->
7171
// TODO support lazily establishing mls group for team 1-1
72-
oneOnOneResolver.resolveOneOnOneConversationWithUser(otherUser).flatMap {
72+
oneOnOneResolver.resolveOneOnOneConversationWithUser(
73+
user = otherUser,
74+
invalidateCurrentKnownProtocols = true
75+
).flatMap {
7376
conversationRepository.getConversationById(it)?.let { Either.Right(it) } ?: Either.Left(StorageFailure.DataNotFound)
7477
}
7578
} ?: Either.Left(StorageFailure.DataNotFound))

logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/NotifyConversationIsOpenUseCase.kt

+4-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@ internal class NotifyConversationIsOpenUseCaseImpl(
6161
kaliumLogger.v(
6262
"Reevaluating protocol for 1:1 conversation with ID: ${conversationId.toLogString()}"
6363
)
64-
oneOnOneResolver.resolveOneOnOneConversationWithUser(conversation.otherUser)
64+
oneOnOneResolver.resolveOneOnOneConversationWithUser(
65+
user = conversation.otherUser,
66+
invalidateCurrentKnownProtocols = true
67+
)
6568
}
6669

6770
// Delete Ephemeral Messages that has passed the end date

logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/mls/OneOnOneResolver.kt

+73-27
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,32 @@ import kotlin.time.Duration
4848
interface OneOnOneResolver {
4949
suspend fun resolveAllOneOnOneConversations(synchronizeUsers: Boolean = false): Either<CoreFailure, Unit>
5050
suspend fun scheduleResolveOneOnOneConversationWithUserId(userId: UserId, delay: Duration = Duration.ZERO): Job
51-
suspend fun resolveOneOnOneConversationWithUserId(userId: UserId): Either<CoreFailure, ConversationId>
52-
suspend fun resolveOneOnOneConversationWithUser(user: OtherUser): Either<CoreFailure, ConversationId>
51+
52+
/**
53+
* Resolves a one-on-one conversation with a user based on their userId.
54+
*
55+
* @param userId The userId of the other user in the conversation.
56+
* @param invalidateCurrentKnownProtocols Flag indicating whether to whether it should attempt refreshing the other user's list of
57+
* supported protocols by fetching from remote. In case of failure, the local result will be used as a fallback.
58+
* @return Either a [CoreFailure] if there is an error or a [ConversationId] if the resolution is successful.
59+
*/
60+
suspend fun resolveOneOnOneConversationWithUserId(
61+
userId: UserId,
62+
invalidateCurrentKnownProtocols: Boolean,
63+
): Either<CoreFailure, ConversationId>
64+
65+
/**
66+
* Resolves a one-on-one conversation with a user.
67+
*
68+
* @param user The other user in the conversation.
69+
* @param invalidateCurrentKnownProtocols Flag indicating whether to whether it should attempt refreshing the other user's list of
70+
* supported protocols by fetching from remote. In case of failure, the local result will be used as a fallback.
71+
* @return Either a [CoreFailure] if there is an error or a [ConversationId] if the resolution is successful.
72+
*/
73+
suspend fun resolveOneOnOneConversationWithUser(
74+
user: OtherUser,
75+
invalidateCurrentKnownProtocols: Boolean,
76+
): Either<CoreFailure, ConversationId>
5377
}
5478

5579
internal class OneOnOneResolverImpl(
@@ -62,52 +86,74 @@ internal class OneOnOneResolverImpl(
6286

6387
@OptIn(ExperimentalCoroutinesApi::class)
6488
private val dispatcher = kaliumDispatcher.default.limitedParallelism(1)
89+
90+
// TODO: inherit the scope of UserSessionScope so it's cancelled if user logs out, etc.
6591
private val resolveActiveOneOnOneScope = CoroutineScope(dispatcher)
6692

6793
override suspend fun resolveAllOneOnOneConversations(synchronizeUsers: Boolean): Either<CoreFailure, Unit> =
68-
if (synchronizeUsers) {
69-
userRepository.fetchAllOtherUsers()
70-
} else {
71-
Either.Right(Unit)
72-
}.flatMap {
94+
fetchAllOtherUsersIfNeeded(synchronizeUsers).flatMap {
7395
val usersWithOneOnOne = userRepository.getUsersWithOneOnOneConversation()
7496
kaliumLogger.i("Resolving one-on-one protocol for ${usersWithOneOnOne.size} user(s)")
7597
usersWithOneOnOne.foldToEitherWhileRight(Unit) { item, _ ->
76-
resolveOneOnOneConversationWithUser(item).flatMapLeft {
77-
when (it) {
78-
is CoreFailure.NoKeyPackagesAvailable,
79-
is NetworkFailure.ServerMiscommunication,
80-
is NetworkFailure.FederatedBackendFailure,
81-
is CoreFailure.NoCommonProtocolFound
82-
-> {
83-
kaliumLogger.e("Resolving one-on-one failed $it, skipping")
84-
Either.Right(Unit)
85-
}
86-
87-
else -> {
88-
kaliumLogger.e("Resolving one-on-one failed $it, retrying")
89-
Either.Left(it)
90-
}
91-
}
98+
resolveOneOnOneConversationWithUser(
99+
user = item,
100+
// Either it fetched all users on the previous step, or it's not needed
101+
invalidateCurrentKnownProtocols = false
102+
).flatMapLeft {
103+
handleBatchEntryFailure(it)
92104
}.map { }
93105
}
94106
}
95107

108+
private fun handleBatchEntryFailure(it: CoreFailure) = when (it) {
109+
is CoreFailure.NoKeyPackagesAvailable,
110+
is NetworkFailure.ServerMiscommunication,
111+
is NetworkFailure.FederatedBackendFailure,
112+
is CoreFailure.NoCommonProtocolFound
113+
-> {
114+
kaliumLogger.e("Resolving one-on-one failed $it, skipping")
115+
Either.Right(Unit)
116+
}
117+
118+
else -> {
119+
kaliumLogger.e("Resolving one-on-one failed $it, retrying")
120+
Either.Left(it)
121+
}
122+
}
123+
124+
private suspend fun fetchAllOtherUsersIfNeeded(synchronizeUsers: Boolean) = if (synchronizeUsers) {
125+
userRepository.fetchAllOtherUsers()
126+
} else {
127+
Either.Right(Unit)
128+
}
129+
96130
override suspend fun scheduleResolveOneOnOneConversationWithUserId(userId: UserId, delay: Duration) =
97131
resolveActiveOneOnOneScope.launch {
98132
kaliumLogger.d("Schedule resolving active one-on-one")
99133
incrementalSyncRepository.incrementalSyncState.first { it is IncrementalSyncStatus.Live }
100134
delay(delay)
101-
resolveOneOnOneConversationWithUserId(userId)
135+
resolveOneOnOneConversationWithUserId(
136+
userId = userId,
137+
invalidateCurrentKnownProtocols = true
138+
)
102139
}
103140

104-
override suspend fun resolveOneOnOneConversationWithUserId(userId: UserId): Either<CoreFailure, ConversationId> =
141+
override suspend fun resolveOneOnOneConversationWithUserId(
142+
userId: UserId,
143+
invalidateCurrentKnownProtocols: Boolean
144+
): Either<CoreFailure, ConversationId> =
105145
userRepository.getKnownUser(userId).firstOrNull()?.let {
106-
resolveOneOnOneConversationWithUser(it)
146+
resolveOneOnOneConversationWithUser(it, invalidateCurrentKnownProtocols)
107147
} ?: Either.Left(StorageFailure.DataNotFound)
108148

109-
override suspend fun resolveOneOnOneConversationWithUser(user: OtherUser): Either<CoreFailure, ConversationId> {
149+
override suspend fun resolveOneOnOneConversationWithUser(
150+
user: OtherUser,
151+
invalidateCurrentKnownProtocols: Boolean,
152+
): Either<CoreFailure, ConversationId> {
110153
kaliumLogger.i("Resolving one-on-one protocol for ${user.id.toLogString()}")
154+
if (invalidateCurrentKnownProtocols) {
155+
userRepository.fetchUsersByIds(setOf(user.id))
156+
}
111157
return oneOnOneProtocolSelector.getProtocolForUser(user.id).flatMap { supportedProtocol ->
112158
when (supportedProtocol) {
113159
SupportedProtocol.PROTEUS -> oneOnOneMigrator.migrateToProteus(user)

logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/UpdateSupportedProtocolsUseCase.kt logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/UpdateSelfUserSupportedProtocolsUseCase.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,16 @@ import kotlinx.datetime.Instant
3939
/**
4040
* Updates the supported protocols of the current user.
4141
*/
42-
interface UpdateSupportedProtocolsUseCase {
42+
interface UpdateSelfUserSupportedProtocolsUseCase {
4343
suspend operator fun invoke(): Either<CoreFailure, Boolean>
4444
}
4545

46-
internal class UpdateSupportedProtocolsUseCaseImpl(
46+
internal class UpdateSelfUserSupportedProtocolsUseCaseImpl(
4747
private val clientsRepository: ClientRepository,
4848
private val userRepository: UserRepository,
4949
private val userConfigRepository: UserConfigRepository,
5050
private val featureSupport: FeatureSupport
51-
) : UpdateSupportedProtocolsUseCase {
51+
) : UpdateSelfUserSupportedProtocolsUseCase {
5252

5353
override suspend operator fun invoke(): Either<CoreFailure, Boolean> {
5454
return if (!featureSupport.isMLSSupported) {

logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/UpdateSupportedProtocolsAndResolveOneOnOnesUseCase.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ interface UpdateSupportedProtocolsAndResolveOneOnOnesUseCase {
3737
}
3838

3939
internal class UpdateSupportedProtocolsAndResolveOneOnOnesUseCaseImpl(
40-
private val updateSupportedProtocols: UpdateSupportedProtocolsUseCase,
40+
private val updateSupportedProtocols: UpdateSelfUserSupportedProtocolsUseCase,
4141
private val oneOnOneResolver: OneOnOneResolver
4242
) : UpdateSupportedProtocolsAndResolveOneOnOnesUseCase {
4343

logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/UserScope.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ class UserScope internal constructor(
9696
private val e2EIRepository: E2EIRepository,
9797
private val mlsConversationRepository: MLSConversationRepository,
9898
private val isSelfATeamMember: IsSelfATeamMemberUseCase,
99-
private val updateSupportedProtocolsUseCase: UpdateSupportedProtocolsUseCase,
99+
private val updateSelfUserSupportedProtocolsUseCase: UpdateSelfUserSupportedProtocolsUseCase,
100100
) {
101101
private val validateUserHandleUseCase: ValidateUserHandleUseCase get() = ValidateUserHandleUseCaseImpl()
102102
val getSelfUser: GetSelfUserUseCase get() = GetSelfUserUseCaseImpl(userRepository)
@@ -179,7 +179,7 @@ class UserScope internal constructor(
179179

180180
val deleteAccount: DeleteAccountUseCase get() = DeleteAccountUseCase(accountRepository)
181181

182-
val updateSupportedProtocols: UpdateSupportedProtocolsUseCase get() = updateSupportedProtocolsUseCase
182+
val updateSupportedProtocols: UpdateSelfUserSupportedProtocolsUseCase get() = updateSelfUserSupportedProtocolsUseCase
183183

184184
val observeCertificateRevocationForSelfClient: ObserveCertificateRevocationForSelfClientUseCase
185185
get() = ObserveCertificateRevocationForSelfClientUseCaseImpl(

logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/receiver/conversation/MLSWelcomeEventHandler.kt

+4-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,10 @@ internal class MLSWelcomeEventHandlerImpl(
101101
.first()
102102
.flatMap {
103103
if (it is ConversationDetails.OneOne) {
104-
oneOnOneResolver.resolveOneOnOneConversationWithUser(it.otherUser).map { Unit }
104+
oneOnOneResolver.resolveOneOnOneConversationWithUser(
105+
user = it.otherUser,
106+
invalidateCurrentKnownProtocols = true
107+
).map { Unit }
105108
} else {
106109
Either.Right(Unit)
107110
}

logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/receiver/conversation/NewConversationEventHandler.kt

+4-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,10 @@ internal class NewConversationEventHandlerImpl(
7676
private suspend fun resolveConversationIfOneOnOne(selfUserTeamId: TeamId?, event: Event.Conversation.NewConversation) =
7777
if (event.conversation.toConversationType(selfUserTeamId) == ConversationEntity.Type.ONE_ON_ONE) {
7878
val otherUserId = event.conversation.members.otherMembers.first().id.toModel()
79-
oneOnOneResolver.resolveOneOnOneConversationWithUserId(otherUserId).map { Unit }
79+
oneOnOneResolver.resolveOneOnOneConversationWithUserId(
80+
userId = otherUserId,
81+
invalidateCurrentKnownProtocols = true
82+
).map { Unit }
8083
} else Either.Right(Unit)
8184

8285
/**

logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncWorker.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import com.wire.kalium.logic.feature.legalhold.FetchLegalHoldForSelfUserFromRemo
3131
import com.wire.kalium.logic.feature.team.SyncSelfTeamUseCase
3232
import com.wire.kalium.logic.feature.user.SyncContactsUseCase
3333
import com.wire.kalium.logic.feature.user.SyncSelfUserUseCase
34-
import com.wire.kalium.logic.feature.user.UpdateSupportedProtocolsUseCase
34+
import com.wire.kalium.logic.feature.user.UpdateSelfUserSupportedProtocolsUseCase
3535
import com.wire.kalium.logic.functional.Either
3636
import com.wire.kalium.logic.functional.flatMap
3737
import com.wire.kalium.logic.functional.foldToEitherWhileRight
@@ -62,7 +62,7 @@ internal class SlowSyncWorkerImpl(
6262
private val eventRepository: EventRepository,
6363
private val syncSelfUser: SyncSelfUserUseCase,
6464
private val syncFeatureConfigs: SyncFeatureConfigsUseCase,
65-
private val updateSupportedProtocols: UpdateSupportedProtocolsUseCase,
65+
private val updateSupportedProtocols: UpdateSelfUserSupportedProtocolsUseCase,
6666
private val syncConversations: SyncConversationsUseCase,
6767
private val syncConnections: SyncConnectionsUseCase,
6868
private val syncSelfTeam: SyncSelfTeamUseCase,

logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/connection/AcceptConnectionRequestUseCaseTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ class AcceptConnectionRequestUseCaseTest {
105105
assertEquals(AcceptConnectionRequestUseCaseResult.Success, result)
106106
verify(arrangement.oneOnOneResolver)
107107
.suspendFunction(arrangement.oneOnOneResolver::resolveOneOnOneConversationWithUserId)
108-
.with(eq(CONNECTION.qualifiedToId))
108+
.with(eq(CONNECTION.qualifiedToId), eq(true))
109109
.wasInvoked(once)
110110
}
111111

0 commit comments

Comments
 (0)