Convert MembershipService to suspend functions

Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
This commit is contained in:
Dominic Fischer 2021-03-28 12:52:12 +01:00
parent 2045a164c1
commit bc68075ae3
12 changed files with 109 additions and 154 deletions

View File

@ -21,6 +21,7 @@ import io.reactivex.Completable
import io.reactivex.Observable
import io.reactivex.Single
import kotlinx.coroutines.rx2.rxCompletable
import kotlinx.coroutines.rx2.rxSingle
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.identity.ThreePid
@ -90,13 +91,13 @@ class RxRoom(private val room: Room) {
return room.getMyReadReceiptLive().asObservable()
}
fun loadRoomMembersIfNeeded(): Single<Unit> = singleBuilder {
room.loadRoomMembersIfNeeded(it)
fun loadRoomMembersIfNeeded(): Single<Unit> = rxSingle {
room.loadRoomMembersIfNeeded()
}
fun joinRoom(reason: String? = null,
viaServers: List<String> = emptyList()): Single<Unit> = singleBuilder {
room.join(reason, viaServers, it)
viaServers: List<String> = emptyList()): Single<Unit> = rxSingle {
room.join(reason, viaServers)
}
fun liveEventReadReceipts(eventId: String): Observable<List<ReadReceipt>> {
@ -114,12 +115,12 @@ class RxRoom(private val room: Room) {
return room.getLiveRoomNotificationState().asObservable()
}
fun invite(userId: String, reason: String? = null): Completable = completableBuilder<Unit> {
room.invite(userId, reason, it)
fun invite(userId: String, reason: String? = null): Completable = rxCompletable {
room.invite(userId, reason)
}
fun invite3pid(threePid: ThreePid): Completable = completableBuilder<Unit> {
room.invite3pid(threePid, it)
fun invite3pid(threePid: ThreePid): Completable = rxCompletable {
room.invite3pid(threePid)
}
fun updateTopic(topic: String): Completable = rxCompletable {

View File

@ -112,8 +112,8 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
bobRoomSummariesLive.observeForever(newRoomObserver)
}
mTestHelper.doSync<Unit> {
aliceRoom.invite(bobSession.myUserId, callback = it)
mTestHelper.runBlockingTest {
aliceRoom.invite(bobSession.myUserId)
}
mTestHelper.await(lock1)
@ -172,8 +172,8 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
fun createSamAccountAndInviteToTheRoom(room: Room): Session {
val samSession = mTestHelper.createAccount(TestConstants.USER_SAM, defaultSessionParams)
mTestHelper.doSync<Unit> {
room.invite(samSession.myUserId, null, it)
mTestHelper.runBlockingTest {
room.invite(samSession.myUserId, null)
}
mTestHelper.doSync<Unit> {
@ -411,7 +411,7 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
val sessions = mutableListOf(aliceSession)
for (index in 1 until numberOfMembers) {
val session = mTestHelper.createAccount("User_$index", defaultSessionParams)
mTestHelper.doSync<Unit>(timeout = 600_000) { room.invite(session.myUserId, null, it) }
mTestHelper.runBlockingTest(timeout = 600_000) { room.invite(session.myUserId, null) }
println("TEST -> " + session.myUserId + " invited")
mTestHelper.doSync<Unit> { session.joinRoom(room.roomId, null, emptyList(), it) }
println("TEST -> " + session.myUserId + " joined")

View File

@ -367,8 +367,8 @@ class KeyShareTests : InstrumentedTest {
}
// Let alice invite bob
mTestHelper.doSync<Unit> {
roomAlicePov.invite(bobSession.myUserId, null, it)
mTestHelper.runBlockingTest {
roomAlicePov.invite(bobSession.myUserId, null)
}
mTestHelper.doSync<Unit> {

View File

@ -17,10 +17,8 @@
package org.matrix.android.sdk.api.session.room.members
import androidx.lifecycle.LiveData
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.session.identity.ThreePid
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
import org.matrix.android.sdk.api.util.Cancelable
/**
* This interface defines methods to handling membership. It's implemented at the room level.
@ -29,9 +27,8 @@ interface MembershipService {
/**
* This methods load all room members if it was done yet.
* @return a [Cancelable]
*/
fun loadRoomMembersIfNeeded(matrixCallback: MatrixCallback<Unit>): Cancelable
suspend fun loadRoomMembersIfNeeded()
/**
* Return the roomMember with userId or null.
@ -60,47 +57,35 @@ interface MembershipService {
/**
* Invite a user in the room
*/
fun invite(userId: String,
reason: String? = null,
callback: MatrixCallback<Unit>): Cancelable
suspend fun invite(userId: String, reason: String? = null)
/**
* Invite a user with email or phone number in the room
*/
fun invite3pid(threePid: ThreePid,
callback: MatrixCallback<Unit>): Cancelable
suspend fun invite3pid(threePid: ThreePid)
/**
* Ban a user from the room
*/
fun ban(userId: String,
reason: String? = null,
callback: MatrixCallback<Unit>): Cancelable
suspend fun ban(userId: String, reason: String? = null)
/**
* Unban a user from the room
*/
fun unban(userId: String,
reason: String? = null,
callback: MatrixCallback<Unit>): Cancelable
suspend fun unban(userId: String, reason: String? = null)
/**
* Kick a user from the room
*/
fun kick(userId: String,
reason: String? = null,
callback: MatrixCallback<Unit>): Cancelable
suspend fun kick(userId: String, reason: String? = null)
/**
* Join the room, or accept an invitation.
*/
fun join(reason: String? = null,
viaServers: List<String> = emptyList(),
callback: MatrixCallback<Unit>): Cancelable
suspend fun join(reason: String? = null, viaServers: List<String> = emptyList())
/**
* Leave the room, or reject an invitation.
*/
fun leave(reason: String? = null,
callback: MatrixCallback<Unit>): Cancelable
suspend fun leave(reason: String? = null)
}

View File

@ -21,13 +21,11 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import dagger.assisted.AssistedFactory
import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.session.identity.ThreePid
import org.matrix.android.sdk.api.session.room.members.MembershipService
import org.matrix.android.sdk.api.session.room.members.RoomMemberQueryParams
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
import org.matrix.android.sdk.api.util.Cancelable
import org.matrix.android.sdk.internal.database.mapper.asDomain
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
@ -39,8 +37,6 @@ import org.matrix.android.sdk.internal.session.room.membership.joining.InviteTas
import org.matrix.android.sdk.internal.session.room.membership.joining.JoinRoomTask
import org.matrix.android.sdk.internal.session.room.membership.leaving.LeaveRoomTask
import org.matrix.android.sdk.internal.session.room.membership.threepid.InviteThreePidTask
import org.matrix.android.sdk.internal.task.TaskExecutor
import org.matrix.android.sdk.internal.task.configureWith
import org.matrix.android.sdk.internal.util.fetchCopied
import io.realm.Realm
import io.realm.RealmQuery
@ -48,7 +44,6 @@ import io.realm.RealmQuery
internal class DefaultMembershipService @AssistedInject constructor(
@Assisted private val roomId: String,
@SessionDatabase private val monarchy: Monarchy,
private val taskExecutor: TaskExecutor,
private val loadRoomMembersTask: LoadRoomMembersTask,
private val inviteTask: InviteTask,
private val inviteThreePidTask: InviteThreePidTask,
@ -64,13 +59,9 @@ internal class DefaultMembershipService @AssistedInject constructor(
fun create(roomId: String): DefaultMembershipService
}
override fun loadRoomMembersIfNeeded(matrixCallback: MatrixCallback<Unit>): Cancelable {
override suspend fun loadRoomMembersIfNeeded() {
val params = LoadRoomMembersTask.Params(roomId, Membership.LEAVE)
return loadRoomMembersTask
.configureWith(params) {
this.callback = matrixCallback
}
.executeBy(taskExecutor)
loadRoomMembersTask.execute(params)
}
override fun getRoomMember(userId: String): RoomMemberSummary? {
@ -120,66 +111,38 @@ internal class DefaultMembershipService @AssistedInject constructor(
}
}
override fun ban(userId: String, reason: String?, callback: MatrixCallback<Unit>): Cancelable {
override suspend fun ban(userId: String, reason: String?) {
val params = MembershipAdminTask.Params(MembershipAdminTask.Type.BAN, roomId, userId, reason)
return membershipAdminTask
.configureWith(params) {
this.callback = callback
}
.executeBy(taskExecutor)
membershipAdminTask.execute(params)
}
override fun unban(userId: String, reason: String?, callback: MatrixCallback<Unit>): Cancelable {
override suspend fun unban(userId: String, reason: String?) {
val params = MembershipAdminTask.Params(MembershipAdminTask.Type.UNBAN, roomId, userId, reason)
return membershipAdminTask
.configureWith(params) {
this.callback = callback
}
.executeBy(taskExecutor)
membershipAdminTask.execute(params)
}
override fun kick(userId: String, reason: String?, callback: MatrixCallback<Unit>): Cancelable {
override suspend fun kick(userId: String, reason: String?) {
val params = MembershipAdminTask.Params(MembershipAdminTask.Type.KICK, roomId, userId, reason)
return membershipAdminTask
.configureWith(params) {
this.callback = callback
}
.executeBy(taskExecutor)
membershipAdminTask.execute(params)
}
override fun invite(userId: String, reason: String?, callback: MatrixCallback<Unit>): Cancelable {
override suspend fun invite(userId: String, reason: String?) {
val params = InviteTask.Params(roomId, userId, reason)
return inviteTask
.configureWith(params) {
this.callback = callback
}
.executeBy(taskExecutor)
inviteTask.execute(params)
}
override fun invite3pid(threePid: ThreePid, callback: MatrixCallback<Unit>): Cancelable {
override suspend fun invite3pid(threePid: ThreePid) {
val params = InviteThreePidTask.Params(roomId, threePid)
return inviteThreePidTask
.configureWith(params) {
this.callback = callback
}
.executeBy(taskExecutor)
return inviteThreePidTask.execute(params)
}
override fun join(reason: String?, viaServers: List<String>, callback: MatrixCallback<Unit>): Cancelable {
override suspend fun join(reason: String?, viaServers: List<String>) {
val params = JoinRoomTask.Params(roomId, reason, viaServers)
return joinTask
.configureWith(params) {
this.callback = callback
}
.executeBy(taskExecutor)
joinTask.execute(params)
}
override fun leave(reason: String?, callback: MatrixCallback<Unit>): Cancelable {
override suspend fun leave(reason: String?) {
val params = LeaveRoomTask.Params(roomId, reason)
return leaveRoomTask
.configureWith(params) {
this.callback = callback
}
.executeBy(taskExecutor)
leaveRoomTask.execute(params)
}
}

View File

@ -940,14 +940,14 @@ class RoomDetailViewModel @AssistedInject constructor(
}
private fun handleInviteSlashCommand(invite: ParsedCommand.Invite) {
launchSlashCommandFlow {
room.invite(invite.userId, invite.reason, it)
launchSlashCommandFlowSuspendable {
room.invite(invite.userId, invite.reason)
}
}
private fun handleInvite3pidSlashCommand(invite: ParsedCommand.Invite3Pid) {
launchSlashCommandFlow {
room.invite3pid(invite.threePid, it)
launchSlashCommandFlowSuspendable {
room.invite3pid(invite.threePid)
}
}
@ -971,20 +971,20 @@ class RoomDetailViewModel @AssistedInject constructor(
}
private fun handleKickSlashCommand(kick: ParsedCommand.KickUser) {
launchSlashCommandFlow {
room.kick(kick.userId, kick.reason, it)
launchSlashCommandFlowSuspendable {
room.kick(kick.userId, kick.reason)
}
}
private fun handleBanSlashCommand(ban: ParsedCommand.BanUser) {
launchSlashCommandFlow {
room.ban(ban.userId, ban.reason, it)
launchSlashCommandFlowSuspendable {
room.ban(ban.userId, ban.reason)
}
}
private fun handleUnbanSlashCommand(unban: ParsedCommand.UnbanUser) {
launchSlashCommandFlow {
room.unban(unban.userId, unban.reason, it)
launchSlashCommandFlowSuspendable {
room.unban(unban.userId, unban.reason)
}
}
@ -1088,11 +1088,21 @@ class RoomDetailViewModel @AssistedInject constructor(
}
private fun handleRejectInvite() {
room.leave(null, NoOpMatrixCallback())
viewModelScope.launch {
try {
room.leave(null)
} catch (_: Exception) {
}
}
}
private fun handleAcceptInvite() {
room.join(callback = NoOpMatrixCallback())
viewModelScope.launch {
try {
room.join()
} catch (_: Exception) {
}
}
}
private fun handleEditAction(action: RoomDetailAction.EnterEditMode) {

View File

@ -26,7 +26,6 @@ import im.vector.app.core.utils.DataSource
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.NoOpMatrixCallback
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.Session
@ -127,17 +126,17 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
return@withState
}
session.getRoom(roomId)?.join(callback = object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
val room = session.getRoom(roomId) ?: return@withState
viewModelScope.launch {
try {
room.join()
// We do not update the joiningRoomsIds here, because, the room is not joined yet regarding the sync data.
// Instead, we wait for the room to be joined
}
override fun onFailure(failure: Throwable) {
} catch (failure: Throwable) {
// Notify the user
_viewEvents.post(RoomListViewEvents.Failure(failure))
}
})
}
}
private fun handleRejectInvitation(action: RoomListAction.RejectInvitation) = withState { state ->
@ -149,19 +148,19 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
return@withState
}
session.getRoom(roomId)?.leave(null, object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
val room = session.getRoom(roomId) ?: return@withState
viewModelScope.launch {
try {
room.leave(null)
// We do not update the rejectingRoomsIds here, because, the room is not rejected yet regarding the sync data.
// Instead, we wait for the room to be rejected
// Known bug: if the user is invited again (after rejecting the first invitation), the loading will be displayed instead of the buttons.
// If we update the state, the button will be displayed again, so it's not ideal...
}
override fun onFailure(failure: Throwable) {
} catch (failure: Throwable) {
// Notify the user
_viewEvents.post(RoomListViewEvents.Failure(failure))
}
})
}
}
private fun handleMarkAllRoomsRead() = withState { state ->
@ -220,15 +219,12 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
private fun handleLeaveRoom(action: RoomListAction.LeaveRoom) {
_viewEvents.post(RoomListViewEvents.Loading(null))
session.getRoom(action.roomId)?.leave(null, object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
_viewEvents.post(RoomListViewEvents.Done)
}
override fun onFailure(failure: Throwable) {
_viewEvents.post(RoomListViewEvents.Failure(failure))
}
})
val room = session.getRoom(action.roomId) ?: return
viewModelScope.launch {
val value = runCatching { room.leave(null) }
.fold({ RoomListViewEvents.Done }, { RoomListViewEvents.Failure(it) })
_viewEvents.post(value)
}
}
private fun observeMembershipChanges() {

View File

@ -23,6 +23,8 @@ import androidx.core.app.RemoteInput
import im.vector.app.R
import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.extensions.vectorComponent
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.NoOpMatrixCallback
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.room.Room
@ -74,15 +76,23 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
private fun handleJoinRoom(roomId: String) {
activeSessionHolder.getSafeActiveSession()?.let { session ->
session.getRoom(roomId)
?.join(callback = NoOpMatrixCallback())
val room = session.getRoom(roomId)
if (room != null) {
GlobalScope.launch {
room.join()
}
}
}
}
private fun handleRejectRoom(roomId: String) {
activeSessionHolder.getSafeActiveSession()?.let { session ->
session.getRoom(roomId)
?.leave(callback = NoOpMatrixCallback())
val room = session.getRoom(roomId)
if (room != null) {
GlobalScope.launch {
room.leave()
}
}
}
}

View File

@ -53,7 +53,6 @@ import org.matrix.android.sdk.api.session.room.powerlevels.Role
import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.api.util.toMatrixItem
import org.matrix.android.sdk.api.util.toOptional
import org.matrix.android.sdk.internal.util.awaitCallback
import org.matrix.android.sdk.rx.rx
import org.matrix.android.sdk.rx.unwrap
@ -198,9 +197,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
viewModelScope.launch {
try {
_viewEvents.post(RoomMemberProfileViewEvents.Loading())
awaitCallback<Unit> {
room.invite(initialState.userId, callback = it)
}
room.invite(initialState.userId)
_viewEvents.post(RoomMemberProfileViewEvents.OnInviteActionSuccess)
} catch (failure: Throwable) {
_viewEvents.post(RoomMemberProfileViewEvents.Failure(failure))
@ -215,9 +212,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
viewModelScope.launch {
try {
_viewEvents.post(RoomMemberProfileViewEvents.Loading())
awaitCallback<Unit> {
room.kick(initialState.userId, action.reason, it)
}
room.kick(initialState.userId, action.reason)
_viewEvents.post(RoomMemberProfileViewEvents.OnKickActionSuccess)
} catch (failure: Throwable) {
_viewEvents.post(RoomMemberProfileViewEvents.Failure(failure))
@ -233,12 +228,10 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
viewModelScope.launch {
try {
_viewEvents.post(RoomMemberProfileViewEvents.Loading())
awaitCallback<Unit> {
if (membership == Membership.BAN) {
room.unban(initialState.userId, action.reason, it)
} else {
room.ban(initialState.userId, action.reason, it)
}
if (membership == Membership.BAN) {
room.unban(initialState.userId, action.reason)
} else {
room.ban(initialState.userId, action.reason)
}
_viewEvents.post(RoomMemberProfileViewEvents.OnBanActionSuccess)
} catch (failure: Throwable) {

View File

@ -32,7 +32,6 @@ import im.vector.app.features.home.ShortcutCreator
import im.vector.app.features.powerlevel.PowerLevelsObservableFactory
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.events.model.EventType
@ -169,15 +168,14 @@ class RoomProfileViewModel @AssistedInject constructor(
private fun handleLeaveRoom() {
_viewEvents.post(RoomProfileViewEvents.Loading(stringProvider.getString(R.string.room_profile_leaving_room)))
room.leave(null, object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
viewModelScope.launch {
try {
room.leave(null)
// Do nothing, we will be closing the room automatically when it will get back from sync
}
override fun onFailure(failure: Throwable) {
} catch (failure: Throwable) {
_viewEvents.post(RoomProfileViewEvents.Failure(failure))
}
})
}
}
private fun handleShareRoomProfile() {

View File

@ -39,7 +39,6 @@ import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
import org.matrix.android.sdk.internal.util.awaitCallback
import org.matrix.android.sdk.rx.rx
import org.matrix.android.sdk.rx.unwrap
@ -124,9 +123,7 @@ class RoomBannedMemberListViewModel @AssistedInject constructor(@Assisted initia
}
viewModelScope.launch(Dispatchers.IO) {
try {
awaitCallback<Unit> {
room.unban(roomMemberSummary.userId, null, it)
}
room.unban(roomMemberSummary.userId, null)
} catch (failure: Throwable) {
_viewEvents.post(RoomBannedMemberListViewEvents.ToastError(stringProvider.getString(R.string.failed_to_unban)))
} finally {

View File

@ -386,7 +386,9 @@ class WidgetPostAPIHandler @AssistedInject constructor(@Assisted private val roo
if (member != null && member.membership == Membership.JOIN) {
widgetPostAPIMediator.sendSuccess(eventData)
} else {
room.invite(userId = userId, callback = createWidgetAPICallback(widgetPostAPIMediator, eventData))
launchWidgetAPIAction(widgetPostAPIMediator, eventData) {
room.invite(userId = userId)
}
}
}