From 6ee98870555b0d830183e8996442f9d28eb6e719 Mon Sep 17 00:00:00 2001 From: Eneko Nieto Date: Sun, 6 Mar 2022 00:32:47 +0100 Subject: [PATCH] Exposed --- build.gradle.kts | 16 +++++++++-- gradle.properties | 4 ++- .../{AppServiceFactory.kt => AppService.kt} | 12 +++----- src/main/kotlin/eu/fosil/okupamicoche/Main.kt | 27 ++++++++++++++++-- .../okupamicoche/services/RoomService.kt | 5 +--- .../okupamicoche/services/UserService.kt | 5 +--- test.mv.db | Bin 0 -> 77824 bytes 7 files changed, 47 insertions(+), 22 deletions(-) rename src/main/kotlin/eu/fosil/okupamicoche/{AppServiceFactory.kt => AppService.kt} (78%) create mode 100644 test.mv.db diff --git a/build.gradle.kts b/build.gradle.kts index 6df2427..137e239 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,19 +11,31 @@ repositories { maven { url = uri("https://maven.pkg.jetbrains.space/public/p/ktor/eap") } } -val ktorVersion = "1.6.7" dependencies { // Ktor + val ktorVersion: String by project implementation("io.ktor:ktor-server-netty:$ktorVersion") implementation("io.ktor:ktor-client-cio:$ktorVersion") // Trixnity - implementation("net.folivo:trixnity-appservice:1.1.6") + implementation("net.folivo:trixnity-appservice:1.1.8") + + // Exposed + val exposedVersion: String by project + dependencies { + implementation("org.jetbrains.exposed:exposed-core:$exposedVersion") + implementation("org.jetbrains.exposed:exposed-dao:$exposedVersion") + implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion") + } + + // H2 database + implementation("com.h2database:h2:2.1.210") // Logger implementation("io.github.microutils:kotlin-logging-jvm:2.1.21") implementation("ch.qos.logback:logback-classic:1.2.10") + // JUnit testImplementation("org.jetbrains.kotlin:kotlin-test-junit:1.6.10") } diff --git a/gradle.properties b/gradle.properties index 29e08e8..673d6f8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,3 @@ -kotlin.code.style=official \ No newline at end of file +kotlin.code.style=official +exposedVersion=0.37.3 +ktorVersion=1.6.7 \ No newline at end of file diff --git a/src/main/kotlin/eu/fosil/okupamicoche/AppServiceFactory.kt b/src/main/kotlin/eu/fosil/okupamicoche/AppService.kt similarity index 78% rename from src/main/kotlin/eu/fosil/okupamicoche/AppServiceFactory.kt rename to src/main/kotlin/eu/fosil/okupamicoche/AppService.kt index ed8d764..10b3454 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/AppServiceFactory.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/AppService.kt @@ -3,7 +3,6 @@ package eu.fosil.okupamicoche import eu.fosil.okupamicoche.services.EventTnxService import eu.fosil.okupamicoche.services.RoomService import eu.fosil.okupamicoche.services.UserService -import io.ktor.http.* import mu.KotlinLogging import net.folivo.trixnity.appservice.rest.AppserviceService import net.folivo.trixnity.appservice.rest.DefaultAppserviceService @@ -14,13 +13,10 @@ import net.folivo.trixnity.core.model.events.m.room.RoomMessageEventContent private val logger = KotlinLogging.logger {} -val matrixClient = MatrixApiClient( - baseUrl = Url("http://okupamicoche-synapse:8008/"), -).apply { accessToken.value = "30c05ae90a248a4188e620216fa72e349803310ec83e2a77b34fe90be6081f46" } +fun createAppService(matrixApiClient:MatrixApiClient): AppserviceService { -fun createAppService(): AppserviceService { val appserviceService = DefaultAppserviceService( - EventTnxService(), UserService(), RoomService() + EventTnxService(), UserService(matrixApiClient), RoomService(matrixApiClient) ) appserviceService.subscribeAllEvents { @@ -39,8 +35,8 @@ fun createAppService(): AppserviceService { if (it.content.body.startsWith("!travel")) { logger.info("send!") - matrixClient.rooms.joinRoom(roomId) - matrixClient.rooms.sendMessageEvent( + matrixApiClient.rooms.joinRoom(roomId) + matrixApiClient.rooms.sendMessageEvent( roomId, RoomMessageEventContent.TextMessageEventContent("Te creo un viaje?") ) diff --git a/src/main/kotlin/eu/fosil/okupamicoche/Main.kt b/src/main/kotlin/eu/fosil/okupamicoche/Main.kt index f523aa3..2086996 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/Main.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/Main.kt @@ -1,34 +1,55 @@ package eu.fosil.okupamicoche +import io.ktor.http.* import io.ktor.server.engine.* import io.ktor.server.netty.* import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.launch import mu.KotlinLogging import net.folivo.trixnity.appservice.rest.MatrixAppserviceProperties import net.folivo.trixnity.appservice.rest.matrixAppserviceModule +import net.folivo.trixnity.client.api.MatrixApiClient import net.folivo.trixnity.client.api.model.rooms.Visibility import net.folivo.trixnity.core.model.RoomAliasId private val logger = KotlinLogging.logger {} suspend fun main() { + + val matrixApiClient = MatrixApiClient( + baseUrl = Url("http://okupamicoche-synapse:8008/"), + ).apply { accessToken.value = "30c05ae90a248a4188e620216fa72e349803310ec83e2a77b34fe90be6081f46" } + coroutineScope { launch { - val roomAliasRes = matrixClient.rooms.getRoomAlias(RoomAliasId("#viajes:okupamicoche-synapse")).getOrNull() + val roomAliasRes = + matrixApiClient.rooms.getRoomAlias(RoomAliasId("#viajes:okupamicoche-synapse")).getOrNull() if (roomAliasRes == null) { logger.info("Creating #viajes:okupamicoche-synapse public room") - matrixClient.rooms.createRoom( + matrixApiClient.rooms.createRoom( visibility = Visibility.PUBLIC, roomAliasId = RoomAliasId("#viajes:okupamicoche-synapse") ) + } else { + val mainRoomId = roomAliasRes.roomId + val alreadyJoinedToMainRoom = (matrixApiClient.rooms.getJoinedRooms().getOrNull()?.filter { roomId -> + roomId == mainRoomId + }?.firstOrNull()) !== null + logger.info("alreadyJoinedToMainRoom=$alreadyJoinedToMainRoom") + + val roomStateRes = matrixApiClient.rooms.getState(mainRoomId).getOrNull() + roomStateRes?.collect { stateEvent -> + logger.debug("stateEvent=$stateEvent") + } } embeddedServer(Netty, port = 8080, host = "0.0.0.0") { matrixAppserviceModule( properties = MatrixAppserviceProperties("312df522183efd404ec1cd22d2ffa4bbc76a8c1ccf541dd692eef281356bb74e"), - appserviceService = createAppService() + appserviceService = createAppService(matrixApiClient) ) }.start(wait = true) } diff --git a/src/main/kotlin/eu/fosil/okupamicoche/services/RoomService.kt b/src/main/kotlin/eu/fosil/okupamicoche/services/RoomService.kt index 81038c1..6488480 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/services/RoomService.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/services/RoomService.kt @@ -1,6 +1,5 @@ package eu.fosil.okupamicoche.services -import eu.fosil.okupamicoche.matrixClient import mu.KotlinLogging import net.folivo.trixnity.appservice.rest.room.AppserviceRoomService import net.folivo.trixnity.appservice.rest.room.CreateRoomParameter @@ -11,9 +10,7 @@ import net.folivo.trixnity.core.model.RoomId private val logger = KotlinLogging.logger {} -class RoomService : AppserviceRoomService { - override val matrixApiClient: MatrixApiClient - get() = matrixClient +class RoomService(override val matrixApiClient: MatrixApiClient) : AppserviceRoomService { override suspend fun getCreateRoomParameter(roomAlias: RoomAliasId): CreateRoomParameter { logger.info("getCreateRoomParameter") diff --git a/src/main/kotlin/eu/fosil/okupamicoche/services/UserService.kt b/src/main/kotlin/eu/fosil/okupamicoche/services/UserService.kt index 638a75b..6b5a266 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/services/UserService.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/services/UserService.kt @@ -1,14 +1,11 @@ package eu.fosil.okupamicoche.services -import eu.fosil.okupamicoche.matrixClient import net.folivo.trixnity.appservice.rest.user.AppserviceUserService import net.folivo.trixnity.appservice.rest.user.RegisterUserParameter import net.folivo.trixnity.client.api.MatrixApiClient import net.folivo.trixnity.core.model.UserId -class UserService : AppserviceUserService { - override val matrixApiClient: MatrixApiClient - get() = matrixClient +class UserService(override val matrixApiClient: MatrixApiClient) : AppserviceUserService { override suspend fun getRegisterUserParameter(userId: UserId): RegisterUserParameter { println("getRegisterUserParameter") diff --git a/test.mv.db b/test.mv.db new file mode 100644 index 0000000000000000000000000000000000000000..e46fcdf831fc01bb3b587b7b10030e48612defc5 GIT binary patch literal 77824 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