diff --git a/.gitignore b/.gitignore index 9aafcc9..3250943 100644 --- a/.gitignore +++ b/.gitignore @@ -6,8 +6,7 @@ build/ !**/src/test/**/build/ # App service DB -matrix.mv.db -matrix.trace.db +okupamicoche.mv.db # Synapse data docker/synapse/data diff --git a/build.gradle.kts b/build.gradle.kts index 137e239..3e595ff 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -31,6 +31,11 @@ dependencies { // H2 database implementation("com.h2database:h2:2.1.210") + // Jackson (YAML parser) + val jacksonVersion: String by project + implementation("com.fasterxml.jackson.module:jackson-module-kotlin:$jacksonVersion") + implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$jacksonVersion") + // Logger implementation("io.github.microutils:kotlin-logging-jvm:2.1.21") implementation("ch.qos.logback:logback-classic:1.2.10") diff --git a/gradle.properties b/gradle.properties index 673d6f8..acf4df6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,4 @@ kotlin.code.style=official exposedVersion=0.37.3 -ktorVersion=1.6.7 \ No newline at end of file +ktorVersion=1.6.7 +jacksonVersion=2.13.1 \ No newline at end of file diff --git a/src/main/kotlin/eu/fosil/okupamicoche/Main.kt b/src/main/kotlin/eu/fosil/okupamicoche/Main.kt index 2086996..efba08b 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/Main.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/Main.kt @@ -1,5 +1,6 @@ package eu.fosil.okupamicoche +import eu.fosil.okupamicoche.config.ConfigReader import io.ktor.http.* import io.ktor.server.engine.* import io.ktor.server.netty.* @@ -18,20 +19,27 @@ private val logger = KotlinLogging.logger {} suspend fun main() { + val config = ConfigReader.load() + + if (config === null) { + logger.error { "Unable to load config" } + return + } + val matrixApiClient = MatrixApiClient( - baseUrl = Url("http://okupamicoche-synapse:8008/"), - ).apply { accessToken.value = "30c05ae90a248a4188e620216fa72e349803310ec83e2a77b34fe90be6081f46" } + baseUrl = Url(config.homeServerUrl), + ).apply { accessToken.value = config.asToken } coroutineScope { launch { val roomAliasRes = - matrixApiClient.rooms.getRoomAlias(RoomAliasId("#viajes:okupamicoche-synapse")).getOrNull() + matrixApiClient.rooms.getRoomAlias(RoomAliasId(config.mainRoomId)).getOrNull() if (roomAliasRes == null) { - logger.info("Creating #viajes:okupamicoche-synapse public room") + logger.info("Creating ${config.mainRoomId} public room") matrixApiClient.rooms.createRoom( visibility = Visibility.PUBLIC, - roomAliasId = RoomAliasId("#viajes:okupamicoche-synapse") + roomAliasId = RoomAliasId(config.mainRoomId) ) } else { val mainRoomId = roomAliasRes.roomId @@ -48,7 +56,7 @@ suspend fun main() { embeddedServer(Netty, port = 8080, host = "0.0.0.0") { matrixAppserviceModule( - properties = MatrixAppserviceProperties("312df522183efd404ec1cd22d2ffa4bbc76a8c1ccf541dd692eef281356bb74e"), + properties = MatrixAppserviceProperties(config.hsToken), appserviceService = createAppService(matrixApiClient) ) }.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 16e1aae..dc9b177 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/cli/CommandParser.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/cli/CommandParser.kt @@ -1,17 +1,14 @@ package eu.fosil.okupamicoche.cli +import eu.fosil.okupamicoche.db import eu.fosil.okupamicoche.model.Travel -import eu.fosil.okupamicoche.model.Travels import io.ktor.http.* import mu.KotlinLogging import net.folivo.trixnity.client.api.MatrixApiClient import net.folivo.trixnity.core.model.RoomId import net.folivo.trixnity.core.model.UserId -import org.jetbrains.exposed.sql.Database -import org.jetbrains.exposed.sql.SchemaUtils +import net.folivo.trixnity.core.model.events.m.room.RoomMessageEventContent import org.jetbrains.exposed.sql.transactions.transaction -import java.text.DateFormat -import java.time.LocalDate import java.time.LocalDateTime import java.time.ZoneOffset import java.time.format.DateTimeFormatter @@ -26,7 +23,7 @@ object CommandParser { fun isCommand(body: String) = body.matches("![a-zA-Z]+( .*)?".toRegex()) - fun parse( + suspend fun parse( user: UserId, room: RoomId, body: String @@ -37,21 +34,25 @@ object CommandParser { handleCommand(user, room, command, args) } - private fun handleCommand( + private suspend fun handleCommand( user: UserId, room: RoomId, command: String, args: List ) { logger.info("command=$command args=$args") - when (command) { - "create" -> handleCreate(user, room, args) + try { + when (command) { + "create" -> handleCreate(user, room, args) + } + } catch (e: Exception) { + logger.error { "Exception captured" } } } - private fun handleCreate( - user: UserId, - room: RoomId, + private suspend fun handleCreate( + userId: UserId, + roomId: RoomId, args: List ) { val origin = args[0] @@ -63,30 +64,26 @@ object CommandParser { val places = args[4].toIntOrNull() ?: 0 val description = args[5] - Database.connect("jdbc:h2:mem:test", driver = "org.h2.Driver") - - transaction { - SchemaUtils.create(Travels) - } - - transaction { + transaction(db) { Travel.new { - this.roomId = room.full - this.driver = user.full + this.roomId = roomId.full + this.driver = userId.full this.origin = origin this.destination = destination this.time = unixTime this.places = places this.description = description } - } - - transaction { - Travel.all().forEach { travel -> - logger.info("travel id=${travel.id} origin=${travel.origin} dest=${travel.destination}") + Travel.all().forEachIndexed { index, travel -> + logger.info("#$index: travel id=${travel.id} origin=${travel.origin} dest=${travel.destination} travel=$travel") } } + val displayName = matrixApiClient.users.getDisplayName(userId).getOrNull() ?: userId.full + matrixApiClient.rooms.sendMessageEvent( + roomId, + RoomMessageEventContent.TextMessageEventContent("$displayName created a new travel! $origin-$destination on $date $time with $places free places.") + ) } diff --git a/src/main/kotlin/eu/fosil/okupamicoche/config/Config.kt b/src/main/kotlin/eu/fosil/okupamicoche/config/Config.kt new file mode 100644 index 0000000..7333d21 --- /dev/null +++ b/src/main/kotlin/eu/fosil/okupamicoche/config/Config.kt @@ -0,0 +1,8 @@ +package eu.fosil.okupamicoche.config + +data class Config( + val mainRoomId: String, + val homeServerUrl: String, + val asToken: String, + val hsToken: String +) \ No newline at end of file diff --git a/src/main/kotlin/eu/fosil/okupamicoche/config/ConfigReader.kt b/src/main/kotlin/eu/fosil/okupamicoche/config/ConfigReader.kt new file mode 100644 index 0000000..6c3ef94 --- /dev/null +++ b/src/main/kotlin/eu/fosil/okupamicoche/config/ConfigReader.kt @@ -0,0 +1,42 @@ +package eu.fosil.okupamicoche.config + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory +import com.fasterxml.jackson.module.kotlin.KotlinModule +import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException +import mu.KotlinLogging +import java.nio.file.Files +import java.nio.file.Paths +import kotlin.io.path.Path + +private val logger = KotlinLogging.logger {} + +object ConfigReader { + + var config: Config? = null + + fun load(): Config? { + val path = this.javaClass.getResource("/config.yaml")?.path + val path2 = Paths.get("/", "config.yaml") + val mapper = ObjectMapper(YAMLFactory()) + mapper.registerModule(KotlinModule()) + + if (path == null) { + logger.error { "Error getting config path" } + return null + } + + config = try { + Files.newBufferedReader(Path(path)).use { + mapper.readValue(it, Config::class.java) + } + } catch (exception: MissingKotlinParameterException) { + logger.error("Could not read YAML file!") + logger.error(exception.message) + null + } + + return config + } + +} \ No newline at end of file diff --git a/src/main/kotlin/eu/fosil/okupamicoche/createAppService.kt b/src/main/kotlin/eu/fosil/okupamicoche/createAppService.kt index 11c885a..5112f85 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/createAppService.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/createAppService.kt @@ -1,6 +1,7 @@ package eu.fosil.okupamicoche import eu.fosil.okupamicoche.cli.CommandParser +import eu.fosil.okupamicoche.model.Travels import eu.fosil.okupamicoche.services.EventTnxService import eu.fosil.okupamicoche.services.RoomService import eu.fosil.okupamicoche.services.UserService @@ -11,11 +12,21 @@ import net.folivo.trixnity.client.api.MatrixApiClient import net.folivo.trixnity.core.model.events.Event import net.folivo.trixnity.core.model.events.m.room.CreateEventContent import net.folivo.trixnity.core.model.events.m.room.RoomMessageEventContent +import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.sql.SchemaUtils +import org.jetbrains.exposed.sql.transactions.transaction + +val db = Database.connect("jdbc:h2:./okupamicoche", driver = "org.h2.Driver") private val logger = KotlinLogging.logger {} fun createAppService(matrixApiClient: MatrixApiClient): AppserviceService { + transaction(db) { + SchemaUtils.create(Travels) + logger.info { "Travels table created" } + } + return DefaultAppserviceService( EventTnxService(), UserService(matrixApiClient), RoomService(matrixApiClient) ).apply { @@ -40,11 +51,6 @@ fun createAppService(matrixApiClient: MatrixApiClient): AppserviceService { roomId, body ) -// matrixApiClient.rooms.joinRoom(roomId) -// matrixApiClient.rooms.sendMessageEvent( -// roomId, -// RoomMessageEventContent.TextMessageEventContent("Viaje creado!") -// ) } } } diff --git a/src/main/resources/config.yaml b/src/main/resources/config.yaml new file mode 100644 index 0000000..f85dbfe --- /dev/null +++ b/src/main/resources/config.yaml @@ -0,0 +1,4 @@ +mainRoomId: "#viajes:okupamicoche-synapse" +homeServerUrl: "http://okupamicoche-synapse:8008/" +asToken: "30c05ae90a248a4188e620216fa72e349803310ec83e2a77b34fe90be6081f46" +hsToken: "312df522183efd404ec1cd22d2ffa4bbc76a8c1ccf541dd692eef281356bb74e" diff --git a/test.mv.db b/test.mv.db deleted file mode 100644 index e46fcdf..0000000 Binary files a/test.mv.db and /dev/null differ