Create local room state events in dedicated task

This commit is contained in:
Florian Renaud 2022-08-10 00:58:18 +02:00
parent 7216f6bd64
commit dee8484618
3 changed files with 303 additions and 260 deletions

View File

@ -43,9 +43,11 @@ import org.matrix.android.sdk.internal.session.room.alias.DefaultGetRoomLocalAli
import org.matrix.android.sdk.internal.session.room.alias.DeleteRoomAliasTask
import org.matrix.android.sdk.internal.session.room.alias.GetRoomIdByAliasTask
import org.matrix.android.sdk.internal.session.room.alias.GetRoomLocalAliasesTask
import org.matrix.android.sdk.internal.session.room.create.CreateLocalRoomStateEventsTask
import org.matrix.android.sdk.internal.session.room.create.CreateLocalRoomTask
import org.matrix.android.sdk.internal.session.room.create.CreateRoomFromLocalRoomTask
import org.matrix.android.sdk.internal.session.room.create.CreateRoomTask
import org.matrix.android.sdk.internal.session.room.create.DefaultCreateLocalRoomStateEventsTask
import org.matrix.android.sdk.internal.session.room.create.DefaultCreateLocalRoomTask
import org.matrix.android.sdk.internal.session.room.create.DefaultCreateRoomFromLocalRoomTask
import org.matrix.android.sdk.internal.session.room.create.DefaultCreateRoomTask
@ -215,6 +217,9 @@ internal abstract class RoomModule {
@Binds
abstract fun bindCreateLocalRoomTask(task: DefaultCreateLocalRoomTask): CreateLocalRoomTask
@Binds
abstract fun bindCreateLocalRoomStateEventsTask(task: DefaultCreateLocalRoomStateEventsTask): CreateLocalRoomStateEventsTask
@Binds
abstract fun bindCreateRoomFromLocalRoomTask(task: DefaultCreateRoomFromLocalRoomTask): CreateRoomFromLocalRoomTask

View File

@ -0,0 +1,296 @@
/*
* Copyright 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.room.create
import org.matrix.android.sdk.api.MatrixPatterns.getServerName
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.events.model.Content
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.LocalEcho
import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.RoomCanonicalAliasContent
import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.api.session.room.model.RoomNameContent
import org.matrix.android.sdk.api.session.room.model.RoomThirdPartyInviteContent
import org.matrix.android.sdk.api.session.room.model.RoomTopicContent
import org.matrix.android.sdk.api.session.room.model.banOrDefault
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
import org.matrix.android.sdk.api.session.room.model.eventsDefaultOrDefault
import org.matrix.android.sdk.api.session.room.model.inviteOrDefault
import org.matrix.android.sdk.api.session.room.model.kickOrDefault
import org.matrix.android.sdk.api.session.room.model.localecho.LocalRoomThirdPartyInviteContent
import org.matrix.android.sdk.api.session.room.model.redactOrDefault
import org.matrix.android.sdk.api.session.room.model.stateDefaultOrDefault
import org.matrix.android.sdk.api.session.room.model.usersDefaultOrDefault
import org.matrix.android.sdk.api.session.user.UserService
import org.matrix.android.sdk.internal.session.room.create.CreateLocalRoomStateEventsTask.Params
import org.matrix.android.sdk.internal.session.room.membership.threepid.toThreePid
import org.matrix.android.sdk.internal.task.Task
import org.matrix.android.sdk.internal.util.time.Clock
import javax.inject.Inject
internal interface CreateLocalRoomStateEventsTask : Task<Params, List<Event>> {
data class Params(
val roomCreatorUserId: String,
val createRoomBody: CreateRoomBody
)
}
internal class DefaultCreateLocalRoomStateEventsTask @Inject constructor(
private val userService: UserService,
private val clock: Clock,
) : CreateLocalRoomStateEventsTask {
private lateinit var createRoomBody: CreateRoomBody
private lateinit var roomCreatorUserId: String
override suspend fun execute(params: Params): List<Event> {
createRoomBody = params.createRoomBody
roomCreatorUserId = params.roomCreatorUserId
return buildList {
createRoomCreateEvent()
createRoomMemberEvents(listOf(roomCreatorUserId))
createRoomPowerLevelsEvent()
createRoomAliasEvent()
createRoomPresetEvents()
createRoomInitialStateEvents()
createRoomNameAndTopicStateEvents()
createRoomMemberEvents(createRoomBody.invitedUserIds.orEmpty())
createRoomThreePidEvents()
createRoomDefaultEvents()
}
}
/**
* Generate the create state event related to this room.
*/
private fun MutableList<Event>.createRoomCreateEvent() = apply {
val roomCreateEvent = createLocalEvent(
type = EventType.STATE_ROOM_CREATE,
content = RoomCreateContent(
creator = roomCreatorUserId,
roomVersion = createRoomBody.roomVersion,
type = (createRoomBody.creationContent as? Map<*, *>)?.get(CreateRoomParams.CREATION_CONTENT_KEY_ROOM_TYPE) as? String
).toContent(),
stateKey = ""
)
add(roomCreateEvent)
}
/**
* Generate the create state event related to the power levels using the given overridden values or the default values according to the specification.
* Ref: https://spec.matrix.org/latest/client-server-api/#mroompower_levels
*/
private fun MutableList<Event>.createRoomPowerLevelsEvent() = apply {
val powerLevelsContent = createLocalEvent(
type = EventType.STATE_ROOM_POWER_LEVELS,
content = (createRoomBody.powerLevelContentOverride ?: PowerLevelsContent()).let {
it.copy(
ban = it.banOrDefault(),
eventsDefault = it.eventsDefaultOrDefault(),
invite = it.inviteOrDefault(),
kick = it.kickOrDefault(),
redact = it.redactOrDefault(),
stateDefault = it.stateDefaultOrDefault(),
usersDefault = it.usersDefaultOrDefault(),
)
}.toContent(),
stateKey = ""
)
add(powerLevelsContent)
}
/**
* Generate the local room member state events related to the given user ids, if any.
*/
private suspend fun MutableList<Event>.createRoomMemberEvents(userIds: List<String>) = apply {
val memberEvents = userIds
.mapNotNull { tryOrNull { userService.resolveUser(it) } }
.map { user ->
createLocalEvent(
type = EventType.STATE_ROOM_MEMBER,
content = RoomMemberContent(
isDirect = createRoomBody.isDirect.takeUnless { user.userId == roomCreatorUserId }.orFalse(),
membership = if (user.userId == roomCreatorUserId) Membership.JOIN else Membership.INVITE,
displayName = user.displayName,
avatarUrl = user.avatarUrl
).toContent(),
stateKey = user.userId
)
}
addAll(memberEvents)
}
/**
* Generate the local state events related to the given third party invites, if any.
*/
private fun MutableList<Event>.createRoomThreePidEvents() = apply {
val threePidEvents = createRoomBody.invite3pids.orEmpty().map { body ->
val localThirdPartyInviteEvent = createLocalEvent(
type = EventType.LOCAL_STATE_ROOM_THIRD_PARTY_INVITE,
content = LocalRoomThirdPartyInviteContent(
isDirect = createRoomBody.isDirect.orFalse(),
membership = Membership.INVITE,
displayName = body.address,
thirdPartyInvite = body.toThreePid()
).toContent(),
stateKey = ""
)
val thirdPartyInviteEvent = createLocalEvent(
type = EventType.STATE_ROOM_THIRD_PARTY_INVITE,
content = RoomThirdPartyInviteContent(body.address, null, null, null).toContent(),
stateKey = ""
)
listOf(localThirdPartyInviteEvent, thirdPartyInviteEvent)
}.flatten()
addAll(threePidEvents)
}
/**
* Generate the local state event related to the given alias, if any.
*/
fun MutableList<Event>.createRoomAliasEvent() = apply {
if (createRoomBody.roomAliasName != null) {
val canonicalAliasContent = createLocalEvent(
type = EventType.STATE_ROOM_CANONICAL_ALIAS,
content = RoomCanonicalAliasContent(
canonicalAlias = "${createRoomBody.roomAliasName}:${roomCreatorUserId.getServerName()}"
).toContent(),
stateKey = ""
)
add(canonicalAliasContent)
}
}
/**
* Generate the local state events related to the given [CreateRoomPreset].
* Ref: https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3createroom
*/
private fun MutableList<Event>.createRoomPresetEvents() = apply {
val preset = createRoomBody.preset ?: return@apply
var joinRules: RoomJoinRules? = null
var historyVisibility: RoomHistoryVisibility? = null
var guestAccess: GuestAccess? = null
when (preset) {
CreateRoomPreset.PRESET_PRIVATE_CHAT,
CreateRoomPreset.PRESET_TRUSTED_PRIVATE_CHAT -> {
joinRules = RoomJoinRules.INVITE
historyVisibility = RoomHistoryVisibility.SHARED
guestAccess = GuestAccess.CanJoin
}
CreateRoomPreset.PRESET_PUBLIC_CHAT -> {
joinRules = RoomJoinRules.PUBLIC
historyVisibility = RoomHistoryVisibility.SHARED
guestAccess = GuestAccess.Forbidden
}
}
add(createLocalEvent(EventType.STATE_ROOM_JOIN_RULES, RoomJoinRulesContent(joinRules.value).toContent(), ""))
add(createLocalEvent(EventType.STATE_ROOM_HISTORY_VISIBILITY, RoomHistoryVisibilityContent(historyVisibility.value).toContent(), ""))
add(createLocalEvent(EventType.STATE_ROOM_GUEST_ACCESS, RoomGuestAccessContent(guestAccess.value).toContent(), ""))
}
/**
* Generate the local state events related to the given initial states, if any.
* The given initial state events override the potential existing ones of the same type.
*/
private fun MutableList<Event>.createRoomInitialStateEvents() = apply {
val initialStates = createRoomBody.initialStates ?: return@apply
val initialStateEvents = initialStates.map { createLocalEvent(it.type, it.content, it.stateKey) }
// Erase existing events of the same type
removeAll { event -> event.type in initialStateEvents.map { it.type } }
// Add the initial state events to the list
addAll(initialStateEvents)
}
/**
* Generate the local events related to the given room name and topic, if any.
*/
private fun MutableList<Event>.createRoomNameAndTopicStateEvents() = apply {
if (createRoomBody.name != null) {
add(createLocalEvent(EventType.STATE_ROOM_NAME, RoomNameContent(createRoomBody.name).toContent(), ""))
}
if (createRoomBody.topic != null) {
add(createLocalEvent(EventType.STATE_ROOM_TOPIC, RoomTopicContent(createRoomBody.topic).toContent(), ""))
}
}
/**
* Generate the local events which have not been set and are in that case provided by the server with default values.
* Default events:
* - m.room.history_visibility (https://spec.matrix.org/latest/client-server-api/#server-behaviour-5)
* - m.room.guest_access (https://spec.matrix.org/latest/client-server-api/#mroomguest_access)
*/
private fun MutableList<Event>.createRoomDefaultEvents() = apply {
// HistoryVisibility
if (none { it.type == EventType.STATE_ROOM_HISTORY_VISIBILITY }) {
add(
createLocalEvent(
type = EventType.STATE_ROOM_HISTORY_VISIBILITY,
content = RoomHistoryVisibilityContent(RoomHistoryVisibility.SHARED.value).toContent(),
stateKey = ""
)
)
}
// GuestAccess
if (none { it.type == EventType.STATE_ROOM_GUEST_ACCESS }) {
add(
createLocalEvent(
type = EventType.STATE_ROOM_GUEST_ACCESS,
content = RoomGuestAccessContent(GuestAccess.Forbidden.value).toContent(),
stateKey = ""
)
)
}
}
/**
* Generate a local event from the given parameters.
*
* @param type the event type, see [EventType]
* @param content the content of the Event
* @param stateKey the stateKey, if any
*
* @return a local event
*/
private fun createLocalEvent(type: String?, content: Content?, stateKey: String?): Event {
return Event(
type = type,
senderId = roomCreatorUserId,
stateKey = stateKey,
content = content,
originServerTs = clock.epochMillis(),
eventId = LocalEcho.createLocalEchoId()
)
}
}

View File

@ -21,43 +21,14 @@ import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.kotlin.createObject
import kotlinx.coroutines.TimeoutCancellationException
import org.matrix.android.sdk.api.MatrixPatterns.getServerName
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.events.model.Content
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.LocalEcho
import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.RoomCanonicalAliasContent
import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.api.session.room.model.RoomNameContent
import org.matrix.android.sdk.api.session.room.model.RoomThirdPartyInviteContent
import org.matrix.android.sdk.api.session.room.model.RoomTopicContent
import org.matrix.android.sdk.api.session.room.model.banOrDefault
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
import org.matrix.android.sdk.api.session.room.model.eventsDefaultOrDefault
import org.matrix.android.sdk.api.session.room.model.inviteOrDefault
import org.matrix.android.sdk.api.session.room.model.kickOrDefault
import org.matrix.android.sdk.api.session.room.model.localecho.LocalRoomThirdPartyInviteContent
import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho
import org.matrix.android.sdk.api.session.room.model.redactOrDefault
import org.matrix.android.sdk.api.session.room.model.stateDefaultOrDefault
import org.matrix.android.sdk.api.session.room.model.usersDefaultOrDefault
import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.api.session.sync.model.RoomSyncSummary
import org.matrix.android.sdk.api.session.user.UserService
import org.matrix.android.sdk.internal.crypto.DefaultCryptoService
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
import org.matrix.android.sdk.internal.database.helper.addTimelineEvent
@ -78,7 +49,6 @@ import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.session.events.getFixedRoomMemberContent
import org.matrix.android.sdk.internal.session.room.membership.RoomMemberEventHandler
import org.matrix.android.sdk.internal.session.room.membership.threepid.toThreePid
import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryUpdater
import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection
import org.matrix.android.sdk.internal.task.Task
@ -96,9 +66,9 @@ internal class DefaultCreateLocalRoomTask @Inject constructor(
private val roomSummaryUpdater: RoomSummaryUpdater,
@SessionDatabase private val realmConfiguration: RealmConfiguration,
private val createRoomBodyBuilder: CreateRoomBodyBuilder,
private val userService: UserService,
private val cryptoService: DefaultCryptoService,
private val clock: Clock,
private val createLocalRoomStateEventsTask: CreateLocalRoomStateEventsTask,
) : CreateLocalRoomTask {
override suspend fun execute(params: CreateRoomParams): String {
@ -186,7 +156,7 @@ internal class DefaultCreateLocalRoomTask @Inject constructor(
isLastForward = true
}
val eventList = createLocalRoomEvents(createRoomBody)
val eventList = createLocalRoomStateEventsTask.execute(CreateLocalRoomStateEventsTask.Params(myUserId, createRoomBody))
val roomMemberContentsByUser = HashMap<String, RoomMemberContent?>()
for (event in eventList) {
@ -226,232 +196,4 @@ internal class DefaultCreateLocalRoomTask @Inject constructor(
return chunkEntity
}
/**
* Build the list of state events related to the room creation body.
* The events list is ordered following the specification: https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3createroom
*
* @param createRoomBody the room creation body
*
* @return the list of events
*/
private suspend fun createLocalRoomEvents(createRoomBody: CreateRoomBody): List<Event> {
return buildList {
createRoomCreateEvent(createRoomBody)
createRoomMemberEvents(listOf(myUserId))
createRoomPowerLevelsEvent(createRoomBody)
createRoomAliasEvent(createRoomBody)
createRoomPresetEvents(createRoomBody)
createRoomInitialStateEvents(createRoomBody)
createRoomNameAndTopicStateEvents(createRoomBody)
createRoomMemberEvents(createRoomBody.invitedUserIds.orEmpty())
createRoomThreePidEvents(createRoomBody)
createRoomDefaultEvents()
}
}
/**
* Generate the create state event related to this room.
*/
private fun MutableList<Event>.createRoomCreateEvent(createRoomBody: CreateRoomBody) = apply {
val roomCreateEvent = createLocalEvent(
type = EventType.STATE_ROOM_CREATE,
content = RoomCreateContent(
creator = myUserId,
roomVersion = createRoomBody.roomVersion,
type = (createRoomBody.creationContent as? Map<*, *>)?.get(CreateRoomParams.CREATION_CONTENT_KEY_ROOM_TYPE) as? String
).toContent(),
stateKey = ""
)
add(roomCreateEvent)
}
/**
* Generate the create state event related to the power levels using the given overridden values or the default values according to the specification.
* Ref: https://spec.matrix.org/latest/client-server-api/#mroompower_levels
*/
private fun MutableList<Event>.createRoomPowerLevelsEvent(createRoomBody: CreateRoomBody) = apply {
val powerLevelsContent = createLocalEvent(
type = EventType.STATE_ROOM_POWER_LEVELS,
content = (createRoomBody.powerLevelContentOverride ?: PowerLevelsContent()).let {
it.copy(
ban = it.banOrDefault(),
eventsDefault = it.eventsDefaultOrDefault(),
invite = it.inviteOrDefault(),
kick = it.kickOrDefault(),
redact = it.redactOrDefault(),
stateDefault = it.stateDefaultOrDefault(),
usersDefault = it.usersDefaultOrDefault(),
)
}.toContent(),
stateKey = ""
)
add(powerLevelsContent)
}
/**
* Generate the local room member state events related to the given user ids, if any.
*/
private suspend fun MutableList<Event>.createRoomMemberEvents(userIds: List<String>, isDirect: Boolean? = null) = apply {
val memberEvents = userIds
.mapNotNull { tryOrNull { userService.resolveUser(it) } }
.map { user ->
createLocalEvent(
type = EventType.STATE_ROOM_MEMBER,
content = RoomMemberContent(
isDirect = isDirect.orFalse(),
membership = if (user.userId == myUserId) Membership.JOIN else Membership.INVITE,
displayName = user.displayName,
avatarUrl = user.avatarUrl
).toContent(),
stateKey = user.userId
)
}
addAll(memberEvents)
}
/**
* Generate the local state events related to the given third party invites, if any.
*/
private fun MutableList<Event>.createRoomThreePidEvents(createRoomBody: CreateRoomBody) = apply {
val threePidEvents = createRoomBody.invite3pids.orEmpty().map { body ->
val localThirdPartyInviteEvent = createLocalEvent(
type = EventType.LOCAL_STATE_ROOM_THIRD_PARTY_INVITE,
content = LocalRoomThirdPartyInviteContent(
isDirect = createRoomBody.isDirect.orFalse(),
membership = Membership.INVITE,
displayName = body.address,
thirdPartyInvite = body.toThreePid()
).toContent(),
stateKey = ""
)
val thirdPartyInviteEvent = createLocalEvent(
type = EventType.STATE_ROOM_THIRD_PARTY_INVITE,
content = RoomThirdPartyInviteContent(body.address, null, null, null).toContent(),
stateKey = ""
)
listOf(localThirdPartyInviteEvent, thirdPartyInviteEvent)
}.flatten()
addAll(threePidEvents)
}
/**
* Generate the local state event related to the given alias, if any.
*/
fun MutableList<Event>.createRoomAliasEvent(createRoomBody: CreateRoomBody) = apply {
if (createRoomBody.roomAliasName != null) {
val canonicalAliasContent = createLocalEvent(
type = EventType.STATE_ROOM_CANONICAL_ALIAS,
content = RoomCanonicalAliasContent(
canonicalAlias = "${createRoomBody.roomAliasName}:${myUserId.getServerName()}"
).toContent(),
stateKey = ""
)
add(canonicalAliasContent)
}
}
/**
* Generate the local state events related to the given [CreateRoomPreset].
* Ref: https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3createroom
*/
private fun MutableList<Event>.createRoomPresetEvents(createRoomBody: CreateRoomBody) = apply {
createRoomBody.preset ?: return@apply
var joinRules: RoomJoinRules? = null
var historyVisibility: RoomHistoryVisibility? = null
var guestAccess: GuestAccess? = null
when (createRoomBody.preset) {
CreateRoomPreset.PRESET_PRIVATE_CHAT,
CreateRoomPreset.PRESET_TRUSTED_PRIVATE_CHAT -> {
joinRules = RoomJoinRules.INVITE
historyVisibility = RoomHistoryVisibility.SHARED
guestAccess = GuestAccess.CanJoin
}
CreateRoomPreset.PRESET_PUBLIC_CHAT -> {
joinRules = RoomJoinRules.PUBLIC
historyVisibility = RoomHistoryVisibility.SHARED
guestAccess = GuestAccess.Forbidden
}
}
add(createLocalEvent(EventType.STATE_ROOM_JOIN_RULES, RoomJoinRulesContent(joinRules.value).toContent(), ""))
add(createLocalEvent(EventType.STATE_ROOM_HISTORY_VISIBILITY, RoomHistoryVisibilityContent(historyVisibility.value).toContent(), ""))
add(createLocalEvent(EventType.STATE_ROOM_GUEST_ACCESS, RoomGuestAccessContent(guestAccess.value).toContent(), ""))
}
/**
* Generate the local state events related to the given initial states, if any.
* The given initial state events override the potential existing ones of the same type.
*/
private fun MutableList<Event>.createRoomInitialStateEvents(createRoomBody: CreateRoomBody) = apply {
createRoomBody.initialStates ?: return@apply
val initialStateEvents = createRoomBody.initialStates.map { createLocalEvent(it.type, it.content, it.stateKey) }
// Erase existing events of the same type
removeAll { event -> event.type in initialStateEvents.map { it.type } }
// Add the initial state events to the list
addAll(initialStateEvents)
}
/**
* Generate the local events related to the given room name and topic, if any.
*/
private fun MutableList<Event>.createRoomNameAndTopicStateEvents(createRoomBody: CreateRoomBody) = apply {
if (createRoomBody.name != null) {
add(createLocalEvent(EventType.STATE_ROOM_NAME, RoomNameContent(createRoomBody.name).toContent(), ""))
}
if (createRoomBody.topic != null) {
add(createLocalEvent(EventType.STATE_ROOM_TOPIC, RoomTopicContent(createRoomBody.topic).toContent(), ""))
}
}
/**
* Generate the local events which have not been set and are in that case provided by the server with default values:
* - m.room.history_visibility (https://spec.matrix.org/latest/client-server-api/#server-behaviour-5)
* - m.room.guest_access (https://spec.matrix.org/latest/client-server-api/#mroomguest_access)
*/
private fun MutableList<Event>.createRoomDefaultEvents() = apply {
// HistoryVisibility
if (none { it.type == EventType.STATE_ROOM_HISTORY_VISIBILITY }) {
add(
createLocalEvent(
type = EventType.STATE_ROOM_HISTORY_VISIBILITY,
content = RoomHistoryVisibilityContent(RoomHistoryVisibility.SHARED.value).toContent(),
stateKey = ""
)
)
}
// GuestAccess
if (none { it.type == EventType.STATE_ROOM_GUEST_ACCESS }) {
add(
createLocalEvent(
type = EventType.STATE_ROOM_GUEST_ACCESS,
content = RoomGuestAccessContent(GuestAccess.Forbidden.value).toContent(),
stateKey = ""
)
)
}
}
/**
* Generate a local event from the given parameters.
*
* @param type the event type, see [EventType]
* @param content the content of the Event
* @param stateKey the stateKey, if any
*
* @return a local event
*/
private fun createLocalEvent(type: String?, content: Content?, stateKey: String?): Event {
return Event(
type = type,
senderId = myUserId,
stateKey = stateKey,
content = content,
originServerTs = clock.epochMillis(),
eventId = LocalEcho.createLocalEchoId()
)
}
}