diff --git a/src/main/kotlin/eu/fosil/okupamicoche/matrix/IMatrixClientServerApiClient.kt b/src/main/kotlin/eu/fosil/okupamicoche/matrix/IMatrixClientServerApiClient.kt new file mode 100644 index 0000000..77f2a78 --- /dev/null +++ b/src/main/kotlin/eu/fosil/okupamicoche/matrix/IMatrixClientServerApiClient.kt @@ -0,0 +1,22 @@ +package eu.fosil.okupamicoche.matrix + +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.serialization.json.Json +import net.folivo.trixnity.clientserverapi.client.* +import net.folivo.trixnity.core.serialization.events.EventContentSerializerMappings + +interface IMatrixClientServerApiClient { + val json: Json + val eventContentSerializerMappings: EventContentSerializerMappings + val accessToken: MutableStateFlow + val httpClient: MatrixClientServerApiHttpClient + val authentication: IAuthenticationApiClient + val server: IServerApiClient + val users: IUsersApiClient + val rooms: IRoomsApiClient + val sync: ISyncApiClient + val keys: IKeysApiClient + val media: IMediaApiClient + val devices: IDevicesApiClient + val push: IPushApiClient +} diff --git a/src/main/kotlin/eu/fosil/okupamicoche/matrix/MatrixApiClient.kt b/src/main/kotlin/eu/fosil/okupamicoche/matrix/MatrixApiClient.kt index b6b39d5..7d4021c 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/matrix/MatrixApiClient.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/matrix/MatrixApiClient.kt @@ -12,8 +12,10 @@ import net.folivo.trixnity.clientserverapi.model.rooms.DirectoryVisibility import net.folivo.trixnity.core.model.RoomAliasId import net.folivo.trixnity.core.model.RoomId import net.folivo.trixnity.core.model.UserId +import net.folivo.trixnity.core.model.events.m.room.Membership import net.folivo.trixnity.core.model.events.m.room.RoomMessageEventContent import net.folivo.trixnity.core.serialization.createEventContentSerializerMappings +import net.folivo.trixnity.core.serialization.createMatrixJson private val logger = KotlinLogging.logger {} @@ -21,6 +23,7 @@ object MatrixApiClient { var appServiceUserId: UserId? = null var mainRoomId: RoomId? = null var client = MatrixClientServerApiClient() + private var config: Config? = null suspend fun init(config: Config) { @@ -30,11 +33,12 @@ object MatrixApiClient { (if (config.homeserver.secure) "https" else "http") + "://${config.homeserver.host}:${config.homeserver.port}" ), + json = createMatrixJson(createEventContentSerializerMappings(TravelEventContentSerializerMappings)), eventContentSerializerMappings = createEventContentSerializerMappings(TravelEventContentSerializerMappings) ).apply { accessToken.value = config.tokens.appService } appServiceUserId = client.authentication.whoAmI().getOrThrow().userId - mainRoomId = createMainRoomIfNeeded() + mainRoomId = createMainRoomIfNeeded(config) } suspend fun getDisplayName(userId: UserId) = @@ -72,9 +76,25 @@ object MatrixApiClient { ) } - private suspend fun createMainRoomIfNeeded(): RoomId? { - val config = requireNotNull(config) + suspend fun getAvailablePlaces(roomId: RoomId): Int? { + // Get travel total places (not counting driver) + val roomState = client.rooms.getStateEvent(roomId).getOrNull() ?: return null + var availablePlaces = roomState.places + + val states = client.rooms.getState(roomId).getOrNull() + logger.info { "states size=${states?.size}" } + + // Remove one place on each Join + client.rooms.getState(roomId).getOrNull()?.filter { + val content = it.content + (content is MembershipStateEventContent) && (content.membership == Membership.JOIN.value) + }?.forEach { _ -> availablePlaces-- } + + return availablePlaces + } + + private suspend fun createMainRoomIfNeeded(config: Config): RoomId? { val mainRoomId: RoomId? val roomMainAlias = "#${config.mainRoom}:${config.homeserver.host}" diff --git a/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelEventContentSerializerMappings.kt b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelEventContentSerializerMappings.kt index 9230436..31a453c 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelEventContentSerializerMappings.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelEventContentSerializerMappings.kt @@ -4,7 +4,7 @@ import eu.fosil.okupamicoche.matrix.event.message.JOIN_MESSAGE_EVENT_TYPE import eu.fosil.okupamicoche.matrix.event.message.JoinMessageEventContent import eu.fosil.okupamicoche.matrix.event.message.TRAVEL_CREATED_MESSAGE_EVENT_TYPE import eu.fosil.okupamicoche.matrix.event.message.TravelCreatedMessageEventContent -import eu.fosil.okupamicoche.matrix.event.state.MEMBERSHIP_CHANGE_STATE_EVENT_TYPE +import eu.fosil.okupamicoche.matrix.event.state.MEMBERSHIP_STATE_EVENT_TYPE import eu.fosil.okupamicoche.matrix.event.state.MembershipStateEventContent import eu.fosil.okupamicoche.matrix.event.state.TRAVEL_CREATED_STATE_EVENT_TYPE import eu.fosil.okupamicoche.matrix.event.state.TravelCreatedStateEventContent @@ -20,6 +20,6 @@ object TravelEventContentSerializerMappings : BaseEventContentSerializerMappings ) override val state: Set> = setOf( EventContentSerializerMapping.of(TRAVEL_CREATED_STATE_EVENT_TYPE), - EventContentSerializerMapping.of(MEMBERSHIP_CHANGE_STATE_EVENT_TYPE) + EventContentSerializerMapping.of(MEMBERSHIP_STATE_EVENT_TYPE) ) } diff --git a/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/state/MembershipStateEventContent.kt b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/state/MembershipStateEventContent.kt index 5b6d469..427bdc9 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/state/MembershipStateEventContent.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/state/MembershipStateEventContent.kt @@ -6,7 +6,7 @@ import net.folivo.trixnity.core.model.UserId import net.folivo.trixnity.core.model.events.StateEventContent import net.folivo.trixnity.core.model.events.m.room.Membership -const val MEMBERSHIP_CHANGE_STATE_EVENT_TYPE = "eu.fosil.travel.member" +const val MEMBERSHIP_STATE_EVENT_TYPE = "eu.fosil.travel.member" @Serializable data class MembershipStateEventContent( diff --git a/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/createTravel.kt b/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/createTravel.kt index ff55ec0..97dd5e1 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/createTravel.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/createTravel.kt @@ -72,8 +72,7 @@ private suspend fun createRoom(travelOptions: TravelOptions, driver: UserId): Ro topic = travelOptions.description, invite = setOf(driver), roomVersion = "9", -// TODO: uncomment when https://gitlab.com/benkuly/trixnity/-/issues/119 gets fixed -// initialState = listOf(initialState), + initialState = listOf(initialState), powerLevelContentOverride = powerLevels ).getOrThrow() @@ -81,7 +80,7 @@ private suspend fun createRoom(travelOptions: TravelOptions, driver: UserId): Ro // https://github.com/vector-im/element-android/issues/3875 // https://github.com/vector-im/element-web/issues/18655 // Send joining rule state event -// matrixApiClient.rooms.sendStateEvent( +// MatrixApiClient.client.rooms.sendStateEvent( // roomId, // JoinRulesEventContent(JoinRulesEventContent.JoinRule.Knock) // ) diff --git a/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/joinTravel.kt b/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/joinTravel.kt index b11c7ec..7d570fe 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/joinTravel.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/joinTravel.kt @@ -31,14 +31,6 @@ private suspend fun sendJoinedMessageEvents( roomId: RoomId, userId: UserId ) { - // Send text message to travel room - val displayName = MatrixApiClient.getDisplayName(userId) - val messageBody = "$displayName joined the travel!" - MatrixApiClient.client.rooms.sendMessageEvent( - roomId, - RoomMessageEventContent.TextMessageEventContent(messageBody) - ) - // Send membership change state event to travel room MatrixApiClient.client.rooms.sendStateEvent( roomId, @@ -46,6 +38,15 @@ private suspend fun sendJoinedMessageEvents( stateKey = userId.full.substring(1) // Synapse throws 403 if stateKey starts with '@' ).getOrThrow() + // Send text message to travel room + val displayName = MatrixApiClient.getDisplayName(userId) + val availablePlaces = MatrixApiClient.getAvailablePlaces(roomId) + val messageBody = "$displayName joined the travel! Places available: $availablePlaces" + MatrixApiClient.client.rooms.sendMessageEvent( + roomId, + RoomMessageEventContent.TextMessageEventContent(messageBody) + ) + // THIS EVENT IS SENT BY CLIENT, NO APP SERVICE // Send new travel message event to main room // matrixApiClient.rooms.sendMessageEvent( diff --git a/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/leaveTravel.kt b/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/leaveTravel.kt index c1c5d34..f54d9ef 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/leaveTravel.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/leaveTravel.kt @@ -37,14 +37,6 @@ private suspend fun sendLeftMessageEvents( roomId: RoomId, userId: UserId ) { - // Send text message to travel room - val displayName = MatrixApiClient.getDisplayName(userId) - val messageBody = "$displayName left the travel." - MatrixApiClient.client.rooms.sendMessageEvent( - roomId, - RoomMessageEventContent.TextMessageEventContent(messageBody) - ) - // Send membership change state event to travel room MatrixApiClient.client.rooms.sendStateEvent( roomId, @@ -52,10 +44,12 @@ private suspend fun sendLeftMessageEvents( stateKey = userId.full.substring(1) // Synapse throws 403 if stateKey starts with '@' ).getOrThrow() - // THIS EVENT IS SENT BY CLIENT, NO APP SERVICE - // Send new travel message event to main room -// matrixApiClient.rooms.sendMessageEvent( -// roomId, -// JoinTravelMessageEventContent(roomId, userId) -// ) + // Send text message to travel room + val displayName = MatrixApiClient.getDisplayName(userId) + val availablePlaces = MatrixApiClient.getAvailablePlaces(roomId) + val messageBody = "$displayName left the travel. Places available: $availablePlaces" + MatrixApiClient.client.rooms.sendMessageEvent( + roomId, + RoomMessageEventContent.TextMessageEventContent(messageBody) + ) }