diff --git a/src/main/kotlin/eu/fosil/okupamicoche/Main.kt b/src/main/kotlin/eu/fosil/okupamicoche/Main.kt index af8f124..5892cd2 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/Main.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/Main.kt @@ -4,7 +4,6 @@ import eu.fosil.okupamicoche.config.ConfigReader import eu.fosil.okupamicoche.matrix.MatrixApiClient import eu.fosil.okupamicoche.matrix.createAppService import eu.fosil.okupamicoche.matrix.event.TravelEventContentSerializerMappings -import eu.fosil.okupamicoche.matrix.matrixApiClient import io.ktor.server.engine.* import io.ktor.server.netty.* import net.folivo.trixnity.applicationserviceapi.server.matrixApplicationServiceApiServer @@ -16,14 +15,13 @@ suspend fun main() { requireNotNull(config) // Init matrix client - requireNotNull(matrixApiClient) - MatrixApiClient.init() + MatrixApiClient.init(config) // Start Ktor server embeddedServer(Netty, port = 8080, host = "0.0.0.0") { matrixApplicationServiceApiServer( hsToken = config.tokens.homeserver, - applicationServiceApiServerHandler = createAppService(matrixApiClient), + applicationServiceApiServerHandler = createAppService(MatrixApiClient.client), customMappings = TravelEventContentSerializerMappings ) }.start(wait = true) diff --git a/src/main/kotlin/eu/fosil/okupamicoche/cli/CommandParser.kt b/src/main/kotlin/eu/fosil/okupamicoche/cli/CommandParser.kt index f6e1b14..c96368b 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/cli/CommandParser.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/cli/CommandParser.kt @@ -1,7 +1,6 @@ package eu.fosil.okupamicoche.cli import eu.fosil.okupamicoche.matrix.MatrixApiClient -import eu.fosil.okupamicoche.matrix.matrixApiClient import eu.fosil.okupamicoche.model.TravelOptions import eu.fosil.okupamicoche.usecase.Usecase import eu.fosil.okupamicoche.usecase.travel.createTravel @@ -39,8 +38,6 @@ object CommandParser { ) { logger.info("command=$command args=$args") try { - requireNotNull(matrixApiClient) - when (command) { "create" -> handleCreate(user, room, args) "join" -> Usecase.joinTravel(room, user) diff --git a/src/main/kotlin/eu/fosil/okupamicoche/matrix/matrixApiClient.kt b/src/main/kotlin/eu/fosil/okupamicoche/matrix/MatrixApiClient.kt similarity index 61% rename from src/main/kotlin/eu/fosil/okupamicoche/matrix/matrixApiClient.kt rename to src/main/kotlin/eu/fosil/okupamicoche/matrix/MatrixApiClient.kt index 11ce3d7..b6b39d5 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/matrix/matrixApiClient.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/matrix/MatrixApiClient.kt @@ -1,6 +1,6 @@ package eu.fosil.okupamicoche.matrix -import eu.fosil.okupamicoche.config.ConfigReader +import eu.fosil.okupamicoche.config.Config import eu.fosil.okupamicoche.matrix.event.TravelEventContentSerializerMappings import eu.fosil.okupamicoche.matrix.event.state.MembershipStateEventContent import eu.fosil.okupamicoche.matrix.event.state.TravelCreatedStateEventContent @@ -17,54 +17,52 @@ import net.folivo.trixnity.core.serialization.createEventContentSerializerMappin private val logger = KotlinLogging.logger {} -val config = ConfigReader.load() -val matrixApiClient = if (config == null) null else MatrixClientServerApiClient( - baseUrl = Url( - (if (config.homeserver.secure) "https" else "http") + - "://${config.homeserver.host}:${config.homeserver.port}" - ), - eventContentSerializerMappings = createEventContentSerializerMappings(TravelEventContentSerializerMappings) -).apply { accessToken.value = config.tokens.appService } - object MatrixApiClient { var appServiceUserId: UserId? = null var mainRoomId: RoomId? = null + var client = MatrixClientServerApiClient() + private var config: Config? = null - suspend fun init() { - requireNotNull(matrixApiClient) + suspend fun init(config: Config) { + this.config = config + client = MatrixClientServerApiClient( + baseUrl = Url( + (if (config.homeserver.secure) "https" else "http") + + "://${config.homeserver.host}:${config.homeserver.port}" + ), + eventContentSerializerMappings = createEventContentSerializerMappings(TravelEventContentSerializerMappings) + ).apply { accessToken.value = config.tokens.appService } - appServiceUserId = matrixApiClient.authentication.whoAmI().getOrThrow().userId + appServiceUserId = client.authentication.whoAmI().getOrThrow().userId mainRoomId = createMainRoomIfNeeded() } suspend fun getDisplayName(userId: UserId) = - matrixApiClient?.users?.getDisplayName(userId)?.getOrNull() ?: userId.localpart + client.users.getDisplayName(userId).getOrNull() ?: userId.localpart suspend fun isTravel(roomId: RoomId) = - matrixApiClient?.rooms?.getStateEvent( + client.rooms.getStateEvent( roomId - )?.getOrNull() !== null + ).getOrNull() !== null suspend fun isDriver(roomId: RoomId, userId: UserId) = - matrixApiClient?.rooms?.getStateEvent( + client.rooms.getStateEvent( roomId - )?.getOrNull()?.driver == userId.full + ).getOrNull()?.driver == userId.full suspend fun getTravelMembership(roomId: RoomId, userId: UserId) = - matrixApiClient?.rooms?.getStateEvent( + client.rooms.getStateEvent( roomId, userId.full.substring(1) // Synapse throws 403 if stateKey starts with '@' - )?.getOrNull()?.membership + ).getOrNull()?.membership suspend fun sendErrorTextMessage( roomId: RoomId, body: String, formattedBody: String? = null ) { - requireNotNull(matrixApiClient) - val formattedBodyWithWarningIcon = "⚠️" + (formattedBody ?: body) - matrixApiClient.rooms.sendMessageEvent( + client.rooms.sendMessageEvent( roomId, RoomMessageEventContent.TextMessageEventContent( body = body, @@ -75,31 +73,30 @@ object MatrixApiClient { } private suspend fun createMainRoomIfNeeded(): RoomId? { - requireNotNull(config) - requireNotNull(matrixApiClient) + val config = requireNotNull(config) val mainRoomId: RoomId? val roomMainAlias = "#${config.mainRoom}:${config.homeserver.host}" - val roomAliasRes = matrixApiClient.rooms.getRoomAlias(RoomAliasId(roomMainAlias)).getOrNull() + val roomAliasRes = client.rooms.getRoomAlias(RoomAliasId(roomMainAlias)).getOrNull() if (roomAliasRes == null) { logger.info("Creating $roomMainAlias public room") - mainRoomId = matrixApiClient.rooms.createRoom( + mainRoomId = client.rooms.createRoom( visibility = DirectoryVisibility.PUBLIC, roomAliasId = RoomAliasId(roomMainAlias) ).getOrNull() } else { mainRoomId = roomAliasRes.roomId - val joinedToMainRoom = (matrixApiClient.rooms.getJoinedRooms().getOrNull()?.firstOrNull { roomId -> + val joinedToMainRoom = (client.rooms.getJoinedRooms().getOrNull()?.firstOrNull { roomId -> roomId == mainRoomId }) !== null logger.info("alreadyJoinedToMainRoom=$joinedToMainRoom") if (!joinedToMainRoom) { - matrixApiClient.rooms.joinRoom(mainRoomId) + client.rooms.joinRoom(mainRoomId) } - val roomStateEvents = matrixApiClient.rooms.getState(mainRoomId).getOrNull() + val roomStateEvents = client.rooms.getState(mainRoomId).getOrNull() roomStateEvents?.forEach { stateEvent -> logger.debug("stateEvent=$stateEvent") } 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 d025dbd..ff55ec0 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/createTravel.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/createTravel.kt @@ -3,12 +3,10 @@ package eu.fosil.okupamicoche.usecase.travel import eu.fosil.okupamicoche.config.ConfigReader import eu.fosil.okupamicoche.db.TravelEntity import eu.fosil.okupamicoche.matrix.MatrixApiClient -import eu.fosil.okupamicoche.matrix.config import eu.fosil.okupamicoche.matrix.db import eu.fosil.okupamicoche.matrix.event.message.TravelCreatedMessageEventContent import eu.fosil.okupamicoche.matrix.event.state.TRAVEL_CREATED_STATE_EVENT_TYPE import eu.fosil.okupamicoche.matrix.event.state.TravelCreatedStateEventContent -import eu.fosil.okupamicoche.matrix.matrixApiClient import eu.fosil.okupamicoche.model.Travel import eu.fosil.okupamicoche.model.TravelOptions import eu.fosil.okupamicoche.usecase.Usecase @@ -52,8 +50,6 @@ suspend fun Usecase.createTravel( } private suspend fun createRoom(travelOptions: TravelOptions, driver: UserId): RoomId { - requireNotNull(matrixApiClient) - requireNotNull(config) val appServiceUserId = requireNotNull(MatrixApiClient.appServiceUserId) val newRoomAliasAndName = getRoomAliasAndName(travelOptions) @@ -69,7 +65,7 @@ private suspend fun createRoom(travelOptions: TravelOptions, driver: UserId): Ro ) ) - return matrixApiClient.rooms.createRoom( + return MatrixApiClient.client.rooms.createRoom( visibility = DirectoryVisibility.PUBLIC, roomAliasId = newRoomAliasAndName.aliasId, name = newRoomAliasAndName.name, @@ -124,9 +120,7 @@ private fun getRoomAliasAttempt(roomAliasPrefix: String, attempt: Int): RoomAlia } private suspend fun isRoomAliasAvailable(roomAliasId: RoomAliasId): Boolean { - requireNotNull(matrixApiClient) - - val roomId = matrixApiClient.rooms.getRoomAlias(roomAliasId).getOrNull() + val roomId = MatrixApiClient.client.rooms.getRoomAlias(roomAliasId).getOrNull() logger.info { "$roomAliasId roomId=$roomId" } return roomId == null @@ -147,7 +141,6 @@ private suspend fun sendCreateMessageEvents( travel: Travel, createdFromRoomId: RoomId ) { - requireNotNull(matrixApiClient) val mainRoomId = requireNotNull(MatrixApiClient.mainRoomId) val instant = Instant.ofEpochMilli(travel.options.time) @@ -158,20 +151,20 @@ private suspend fun sendCreateMessageEvents( val displayName = MatrixApiClient.getDisplayName(travel.driver) val messageBody = "$displayName created a new travel! ${travel.options.from}-${travel.options.to}" + " on $date $time with ${travel.options.places} free places." - matrixApiClient.rooms.sendMessageEvent( + MatrixApiClient.client.rooms.sendMessageEvent( mainRoomId, RoomMessageEventContent.TextMessageEventContent(messageBody) ) // Send new travel message event to main room - matrixApiClient.rooms.sendMessageEvent( + MatrixApiClient.client.rooms.sendMessageEvent( mainRoomId, TravelCreatedMessageEventContent(travel) ) // Send text message to room where create command was sent (if it is not main room) if (createdFromRoomId != mainRoomId) { - matrixApiClient.rooms.sendMessageEvent( + MatrixApiClient.client.rooms.sendMessageEvent( createdFromRoomId, RoomMessageEventContent.TextMessageEventContent(messageBody) ) 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 02a2307..b11c7ec 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/joinTravel.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/joinTravel.kt @@ -2,7 +2,6 @@ package eu.fosil.okupamicoche.usecase.travel import eu.fosil.okupamicoche.matrix.MatrixApiClient import eu.fosil.okupamicoche.matrix.event.state.MembershipStateEventContent -import eu.fosil.okupamicoche.matrix.matrixApiClient import eu.fosil.okupamicoche.usecase.Usecase import net.folivo.trixnity.core.model.RoomId import net.folivo.trixnity.core.model.UserId @@ -13,7 +12,6 @@ suspend fun Usecase.joinTravel( roomId: RoomId, userId: UserId ) { - requireNotNull(matrixApiClient) val isTravel = MatrixApiClient.isTravel(roomId) val isDriver = MatrixApiClient.isDriver(roomId, userId) val membershipState = MatrixApiClient.getTravelMembership(roomId, userId) @@ -23,7 +21,7 @@ suspend fun Usecase.joinTravel( } else if (isDriver) { MatrixApiClient.sendErrorTextMessage(roomId, "You are the driver, you don't need to join.") } else if (membershipState == Membership.JOIN.value) { - MatrixApiClient.sendErrorTextMessage(roomId, "You were already joined.") + MatrixApiClient.sendErrorTextMessage(roomId, "You are already joined.") } else { sendJoinedMessageEvents(roomId, userId) } @@ -33,18 +31,16 @@ private suspend fun sendJoinedMessageEvents( roomId: RoomId, userId: UserId ) { - requireNotNull(matrixApiClient) - // Send text message to travel room val displayName = MatrixApiClient.getDisplayName(userId) val messageBody = "$displayName joined the travel!" - matrixApiClient.rooms.sendMessageEvent( + MatrixApiClient.client.rooms.sendMessageEvent( roomId, RoomMessageEventContent.TextMessageEventContent(messageBody) ) // Send membership change state event to travel room - matrixApiClient.rooms.sendStateEvent( + MatrixApiClient.client.rooms.sendStateEvent( roomId, MembershipStateEventContent(userId, Membership.JOIN), stateKey = userId.full.substring(1) // Synapse throws 403 if stateKey starts with '@' 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 b04dc18..c1c5d34 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/leaveTravel.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/leaveTravel.kt @@ -2,7 +2,6 @@ package eu.fosil.okupamicoche.usecase.travel import eu.fosil.okupamicoche.matrix.MatrixApiClient import eu.fosil.okupamicoche.matrix.event.state.MembershipStateEventContent -import eu.fosil.okupamicoche.matrix.matrixApiClient import eu.fosil.okupamicoche.usecase.Usecase import net.folivo.trixnity.core.model.RoomId import net.folivo.trixnity.core.model.UserId @@ -13,7 +12,6 @@ suspend fun Usecase.leaveTravel( roomId: RoomId, userId: UserId ) { - requireNotNull(matrixApiClient) val isTravel = MatrixApiClient.isTravel(roomId) val isDriver = MatrixApiClient.isDriver(roomId, userId) val membershipState = MatrixApiClient.getTravelMembership(roomId, userId) @@ -39,18 +37,16 @@ private suspend fun sendLeftMessageEvents( roomId: RoomId, userId: UserId ) { - requireNotNull(matrixApiClient) - // Send text message to travel room val displayName = MatrixApiClient.getDisplayName(userId) val messageBody = "$displayName left the travel." - matrixApiClient.rooms.sendMessageEvent( + MatrixApiClient.client.rooms.sendMessageEvent( roomId, RoomMessageEventContent.TextMessageEventContent(messageBody) ) // Send membership change state event to travel room - matrixApiClient.rooms.sendStateEvent( + MatrixApiClient.client.rooms.sendStateEvent( roomId, MembershipStateEventContent(userId, Membership.LEAVE), stateKey = userId.full.substring(1) // Synapse throws 403 if stateKey starts with '@'