Author SHA1 Message Date
flecomte 774e80d9d5 feature: init kotlin compose multiplatforme
Tests / build (pull_request) Successful in 7m44s
Tests / test (pull_request) Failing after 10m37s
Tests / lint (pull_request) Successful in 14m30s
2026-08-06 21:28:57 +02:00
196 changed files with 1297 additions and 688 deletions
+8 -4
View File
@@ -70,13 +70,17 @@ jobs:
run: chmod +x gradlew
- name: Run lint
run: ./gradlew ktlintCheck
# Path scoped to :backend on purpose: :composeApp applies the Android Gradle plugin,
# which needs an Android SDK to even configure. Keeping every gradlew invocation on a
# fully-qualified project path (with org.gradle.configureondemand=true) lets CI skip
# configuring :composeApp entirely, so no Android SDK setup is needed on this runner.
run: ./gradlew :backend:ktlintCheck
- name: Publish ktlint report
uses: yutailang0119/action-ktlint@v5
if: always()
with:
report-path: build/reports/ktlint/**/*.xml
report-path: backend/build/reports/ktlint/**/*.xml
continue-on-error: false
test:
@@ -128,12 +132,12 @@ jobs:
uses: actions/upload-artifact@v7
with:
name: test-results
path: build/reports/tests/test
path: backend/build/reports/tests/test
- name: Publish Test Report
uses: dorny/test-reporter@v3
if: always()
with:
name: JUnit Tests
path: build/test-results/test/TEST-*.xml
path: backend/build/test-results/test/TEST-*.xml
reporter: java-junit
+6
View File
@@ -1,9 +1,15 @@
.gradle
.kotlin/
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### Android / KMP ###
local.properties
captures/
.cxx/
### STS ###
.apt_generated
.classpath
+105
View File
@@ -0,0 +1,105 @@
import org.jlleitschuh.gradle.ktlint.KtlintExtension
val ktorVersion: Provider<String> = providers.gradleProperty("ktor_version")
val kotlinVersion: Provider<String> = providers.gradleProperty("kotlin_version")
val kotlinSerializationVersion: Provider<String> = providers.gradleProperty("kotlin_serialization_version")
val logbackVersion: Provider<String> = providers.gradleProperty("logback_version")
val koinVersion: Provider<String> = providers.gradleProperty("koin_version")
val kotlinLoggingVersion: Provider<String> = providers.gradleProperty("kotlin_logging_version")
val kotestVersion: Provider<String> = providers.gradleProperty("kotest_version")
plugins {
application
kotlin("jvm")
id("io.ktor.plugin") version "3.5.1"
id("org.jetbrains.kotlin.plugin.serialization")
id("org.jlleitschuh.gradle.ktlint") version "14.2.0"
}
group = "io.github.flecomte"
application {
mainClass.set("eventDemo.ApplicationKt")
val isDevelopment: Boolean = project.ext.has("development")
applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment")
}
configure<KtlintExtension> {
version.set("1.8.0")
}
ktlint {
reporters {
reporter(org.jlleitschuh.gradle.ktlint.reporter.ReporterType.CHECKSTYLE)
}
}
repositories {
mavenCentral()
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
kotlin {
compilerOptions {
freeCompilerArgs.add("-opt-in=kotlin.uuid.ExperimentalUuidApi")
}
}
tasks.withType<Test>().configureEach {
useJUnitPlatform()
jvmArgs("-Djdk.attach.allowAttachSelf=true", "-XX:+EnableDynamicAgentLoading")
// Dynamic self-attach (used by MockK/ByteBuddy) times out in Docker containers because the
// SIGQUIT-triggered AttachListener handshake never completes there. Loading the byte-buddy
// agent jar statically via -javaagent avoids the attach handshake entirely: MockK detects the
// pre-installed Instrumentation instance and skips dynamic attach.
doFirst {
val agentJar =
classpath.files.firstOrNull { it.name.startsWith("byte-buddy-agent") }
?: error("byte-buddy-agent jar not found on test classpath")
jvmArgs("-javaagent:$agentJar")
}
}
dependencies {
implementation(project(":shared"))
implementation("io.ktor:ktor-server-core-jvm")
implementation("io.ktor:ktor-server-auth-jvm")
implementation("io.ktor:ktor-server-auth-jwt-jvm")
implementation("io.ktor:ktor-server-auto-head-response-jvm")
implementation("io.ktor:ktor-server-resources")
implementation("io.ktor:ktor-server-content-negotiation-jvm")
implementation("io.ktor:ktor-serialization-kotlinx-json-jvm")
implementation("io.ktor:ktor-server-websockets-jvm")
implementation("io.ktor:ktor-server-cors-jvm")
implementation("io.ktor:ktor-server-host-common-jvm")
implementation("io.ktor:ktor-server-status-pages-jvm")
implementation("io.ktor:ktor-server-netty-jvm")
implementation("io.ktor:ktor-server-data-conversion")
implementation("io.ktor:ktor-client-content-negotiation")
implementation("io.ktor:ktor-client-auth")
implementation("ch.qos.logback:logback-classic:${logbackVersion.get()}")
implementation("io.insert-koin:koin-ktor:${koinVersion.get()}")
implementation("io.insert-koin:koin-logger-slf4j:${koinVersion.get()}")
implementation("io.github.oshai:kotlin-logging-jvm:${kotlinLoggingVersion.get()}")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:${kotlinSerializationVersion.get()}")
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.2")
implementation("org.postgresql:postgresql:42.7.13")
implementation("com.zaxxer:HikariCP:6.3.0")
implementation("com.rabbitmq:amqp-client:5.25.0")
implementation("com.password4j:password4j:1.8.4")
// Force version of sub library (for security)
implementation("commons-codec:commons-codec:1.13")
testImplementation("io.kotest:kotest-extensions-koin:${kotestVersion.get()}")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:${kotlinVersion.get()}")
testImplementation("io.ktor:ktor-server-test-host-jvm:${ktorVersion.get()}")
testImplementation("io.kotest:kotest-runner-junit5:${kotestVersion.get()}")
testImplementation("io.mockk:mockk:1.14.11")
testImplementation("com.tngtech.archunit:archunit-junit5:1.3.0")
}
@@ -2,7 +2,7 @@ package eventDemo.contexts.auth.application.eventStores
import eventDemo.contexts.auth.application.ports.UserEventStore
import eventDemo.contexts.auth.domain.User
import eventDemo.sharedKernel.UserId
import eventDemo.shared.ids.UserId
class UserEventStoreRepository(
val eventStore: UserEventStore,
@@ -1,7 +1,7 @@
package eventDemo.contexts.auth.application.eventStores
import eventDemo.contexts.auth.domain.User
import eventDemo.sharedKernel.UserId
import eventDemo.shared.ids.UserId
interface UserRepository {
fun get(id: UserId): User?
@@ -2,6 +2,6 @@ package eventDemo.contexts.auth.application.ports
import eventDemo.contexts.auth.domain.events.UserEvent
import eventDemo.libs.eventSource.eventStore.EventStore
import eventDemo.sharedKernel.UserId
import eventDemo.shared.ids.UserId
interface UserEventStore : EventStore<UserEvent, UserId>
@@ -2,7 +2,7 @@ package eventDemo.contexts.auth.domain
import eventDemo.contexts.auth.domain.events.NewUserCreatedEvent
import eventDemo.contexts.auth.domain.events.UserEvent
import eventDemo.sharedKernel.UserId
import eventDemo.shared.ids.UserId
import kotlinx.serialization.Serializable
@Serializable
@@ -1,7 +1,7 @@
package eventDemo.contexts.auth.domain.events
import eventDemo.libs.eventSource.EventId
import eventDemo.sharedKernel.UserId
import eventDemo.shared.ids.EventId
import eventDemo.shared.ids.UserId
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
@@ -1,7 +1,7 @@
package eventDemo.contexts.auth.domain.events
import eventDemo.libs.eventSource.Event
import eventDemo.sharedKernel.UserId
import eventDemo.shared.ids.UserId
import kotlinx.serialization.Serializable
@Serializable
@@ -5,7 +5,7 @@ import com.auth0.jwt.algorithms.Algorithm
import eventDemo.configuration.configuration
import eventDemo.contexts.auth.domain.User
import eventDemo.contexts.auth.infrastructure.persistence.projection.UserProjection
import eventDemo.sharedKernel.UserId
import eventDemo.shared.ids.UserId
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.Application
import io.ktor.server.auth.authentication
@@ -4,7 +4,7 @@ import eventDemo.contexts.auth.application.ports.UserEventStore
import eventDemo.contexts.auth.domain.events.UserEvent
import eventDemo.libs.eventSource.eventStore.EventStore
import eventDemo.libs.eventSource.eventStore.EventStoreInMemory
import eventDemo.sharedKernel.UserId
import eventDemo.shared.ids.UserId
/**
* A stream to publish and read the user events.
@@ -4,7 +4,7 @@ import eventDemo.contexts.auth.application.ports.UserEventStore
import eventDemo.contexts.auth.domain.events.UserEvent
import eventDemo.libs.eventSource.eventStore.EventStore
import eventDemo.libs.eventSource.eventStore.EventStoreInPostgresql
import eventDemo.sharedKernel.UserId
import eventDemo.shared.ids.UserId
import kotlinx.serialization.json.Json
import javax.sql.DataSource
@@ -1,6 +1,6 @@
package eventDemo.contexts.auth.infrastructure.persistence.projection
import eventDemo.sharedKernel.UserId
import eventDemo.shared.ids.UserId
data class UserProjection(
val id: UserId,
@@ -3,9 +3,10 @@ package eventDemo.contexts.auth.infrastructure.persistence.projection
import eventDemo.contexts.auth.application.ports.UserProjectionRepository
import eventDemo.contexts.auth.infrastructure.checkPassword
import eventDemo.contexts.auth.infrastructure.hashPassword
import eventDemo.sharedKernel.UserId
import java.util.UUID
import eventDemo.shared.ids.UserId
import javax.sql.DataSource
import kotlin.uuid.Uuid
import kotlin.uuid.toJavaUuid
class UserProjectionRepositoryInPostgresql(
val dataSource: DataSource,
@@ -24,7 +25,7 @@ class UserProjectionRepositoryInPostgresql(
}.use { resultSet ->
if (resultSet.next()) {
UserProjection(
id = UserId(UUID.fromString(resultSet.getString("id"))),
id = UserId(Uuid.parse(resultSet.getString("id"))),
username = resultSet.getString("username"),
password = resultSet.getString("password"),
)
@@ -42,7 +43,7 @@ class UserProjectionRepositoryInPostgresql(
values (?, ?)
""".trimIndent(),
).use {
it.setObject(1, user.id)
it.setObject(1, user.id.id.toJavaUuid())
it.setString(2, user.username)
it.executeUpdate()
}
@@ -1,11 +1,11 @@
package eventDemo.contexts.game.application.channels
import eventDemo.contexts.game.application.command.models.GameCommand
import eventDemo.contexts.game.application.notification.CommandSubscriber
import eventDemo.contexts.game.application.notification.EventToNotificationSubscriber
import eventDemo.contexts.game.application.notification.models.Notification
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.sharedKernel.UserId
import eventDemo.shared.game.command.GameCommand
import eventDemo.shared.game.notification.Notification
import eventDemo.shared.ids.GameId
import eventDemo.shared.ids.UserId
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.SendChannel
@@ -1,11 +1,11 @@
package eventDemo.contexts.game.application.command.handlers
import eventDemo.contexts.game.application.command.models.GameCommand
import eventDemo.contexts.game.application.command.models.JoinTheGameCommand
import eventDemo.contexts.game.application.command.models.PlayCardCommand
import eventDemo.contexts.game.application.command.models.ReadyToPlayCommand
import eventDemo.contexts.game.application.command.models.TakeCartFromDrawPileCommand
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.shared.game.command.GameCommand
import eventDemo.shared.game.command.JoinTheGameCommand
import eventDemo.shared.game.command.PlayCardCommand
import eventDemo.shared.game.command.ReadyToPlayCommand
import eventDemo.shared.game.command.TakeCartFromDrawPileCommand
import eventDemo.shared.ids.GameId
import java.util.Collections
class GameCommandHandlerDispatcher(
@@ -1,12 +1,12 @@
package eventDemo.contexts.game.application.command.handlers
import eventDemo.contexts.game.application.command.models.GameCommand
import eventDemo.contexts.game.application.eventStores.GameRepository
import eventDemo.contexts.game.application.ports.GameEventBus
import eventDemo.contexts.game.domain.events.GameEvent
import eventDemo.contexts.game.domain.game.gameState.Game
import eventDemo.libs.command.Command
import eventDemo.libs.eventSource.eventStore.VersionConflictException
import eventDemo.shared.command.Command
import eventDemo.shared.game.command.GameCommand
import io.github.oshai.kotlinlogging.KotlinLogging
import kotlin.reflect.KClass
@@ -1,10 +1,10 @@
package eventDemo.contexts.game.application.command.handlers
import eventDemo.contexts.auth.application.eventStores.UserRepository
import eventDemo.contexts.game.application.command.models.JoinTheGameCommand
import eventDemo.contexts.game.application.eventStores.GameRepository
import eventDemo.contexts.game.application.ports.GameEventBus
import eventDemo.contexts.game.domain.game.gameState.GameCreated
import eventDemo.shared.game.command.JoinTheGameCommand
/**
* A command to perform an action to play a new card
@@ -1,9 +1,9 @@
package eventDemo.contexts.game.application.command.handlers
import eventDemo.contexts.game.application.command.models.PlayCardCommand
import eventDemo.contexts.game.application.eventStores.GameRepository
import eventDemo.contexts.game.application.ports.GameEventBus
import eventDemo.contexts.game.domain.game.gameState.GameStarted
import eventDemo.shared.game.command.PlayCardCommand
/**
* A command to perform an action to play a new card
@@ -1,9 +1,9 @@
package eventDemo.contexts.game.application.command.handlers
import eventDemo.contexts.game.application.command.models.ReadyToPlayCommand
import eventDemo.contexts.game.application.eventStores.GameRepository
import eventDemo.contexts.game.application.ports.GameEventBus
import eventDemo.contexts.game.domain.game.gameState.GameCreated
import eventDemo.shared.game.command.ReadyToPlayCommand
/**
* A command to set as ready to play
@@ -1,9 +1,9 @@
package eventDemo.contexts.game.application.command.handlers
import eventDemo.contexts.game.application.command.models.TakeCartFromDrawPileCommand
import eventDemo.contexts.game.application.eventStores.GameRepository
import eventDemo.contexts.game.application.ports.GameEventBus
import eventDemo.contexts.game.domain.game.gameState.GameStarted
import eventDemo.shared.game.command.TakeCartFromDrawPileCommand
/**
* A command to draw card on draw pile.
@@ -1,9 +1,9 @@
package eventDemo.contexts.game.application.eventStores
import eventDemo.contexts.game.application.ports.GameEventStore
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.domain.game.gameState.Game
import eventDemo.libs.eventSource.eventStore.VersionConflictException
import eventDemo.shared.ids.GameId
class GameEventStoreRepository(
val eventStore: GameEventStore,
@@ -1,10 +1,10 @@
package eventDemo.contexts.game.application.eventStores
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.domain.game.gameState.Game
import eventDemo.contexts.game.domain.game.gameState.GameCreated
import eventDemo.contexts.game.domain.game.gameState.GameInit
import eventDemo.libs.eventSource.eventStore.VersionConflictException
import eventDemo.shared.ids.GameId
interface GameRepository {
fun get(id: GameId): Game?
@@ -1,16 +1,5 @@
package eventDemo.contexts.game.application.notification
import eventDemo.contexts.game.application.notification.models.ItsTheTurnOfNotification
import eventDemo.contexts.game.application.notification.models.Notification
import eventDemo.contexts.game.application.notification.models.PilesShuffledNotification
import eventDemo.contexts.game.application.notification.models.PlayerAsJoinTheGameNotification
import eventDemo.contexts.game.application.notification.models.PlayerAsPlayACardNotification
import eventDemo.contexts.game.application.notification.models.PlayerHavePassNotification
import eventDemo.contexts.game.application.notification.models.PlayerWasReadyNotification
import eventDemo.contexts.game.application.notification.models.PlayerWinNotification
import eventDemo.contexts.game.application.notification.models.TheGameWasStartedNotification
import eventDemo.contexts.game.application.notification.models.WelcomeToTheGameNotification
import eventDemo.contexts.game.application.notification.models.YourNewCardNotification
import eventDemo.contexts.game.domain.events.CardIsPlayedEvent
import eventDemo.contexts.game.domain.events.DrawFilledWithDiscardEvent
import eventDemo.contexts.game.domain.events.GameCreatedEvent
@@ -23,7 +12,18 @@ import eventDemo.contexts.game.domain.events.PlayerReadyEvent
import eventDemo.contexts.game.domain.events.PlayerWinEvent
import eventDemo.contexts.game.domain.game.gameState.Game
import eventDemo.contexts.game.domain.game.gameState.GameStarted
import eventDemo.sharedKernel.UserId
import eventDemo.shared.game.notification.ItsTheTurnOfNotification
import eventDemo.shared.game.notification.Notification
import eventDemo.shared.game.notification.PilesShuffledNotification
import eventDemo.shared.game.notification.PlayerAsJoinTheGameNotification
import eventDemo.shared.game.notification.PlayerAsPlayACardNotification
import eventDemo.shared.game.notification.PlayerHavePassNotification
import eventDemo.shared.game.notification.PlayerWasReadyNotification
import eventDemo.shared.game.notification.PlayerWinNotification
import eventDemo.shared.game.notification.TheGameWasStartedNotification
import eventDemo.shared.game.notification.WelcomeToTheGameNotification
import eventDemo.shared.game.notification.YourNewCardNotification
import eventDemo.shared.ids.UserId
import io.github.oshai.kotlinlogging.KotlinLogging
import io.github.oshai.kotlinlogging.withLoggingContext
@@ -1,7 +1,6 @@
package eventDemo.contexts.game.application.notification
import eventDemo.contexts.game.application.command.handlers.GameCommandHandlerDispatcher
import eventDemo.contexts.game.application.command.models.GameCommand
import eventDemo.contexts.game.application.eventStores.GameRepository
import eventDemo.contexts.game.application.logging.LoggingContextKeys.Command
import eventDemo.contexts.game.application.logging.LoggingContextKeys.CurrentUserId
@@ -9,12 +8,13 @@ import eventDemo.contexts.game.application.logging.LoggingContextKeys.Event
import eventDemo.contexts.game.application.logging.LoggingContextKeys.Game
import eventDemo.contexts.game.application.logging.LoggingContextKeys.Notification
import eventDemo.contexts.game.application.logging.withLoggingContext
import eventDemo.contexts.game.application.notification.models.Notification
import eventDemo.contexts.game.application.ports.GameEventBus
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.libs.bus.Bus
import eventDemo.libs.command.CommandUnicityChecker
import eventDemo.sharedKernel.UserId
import eventDemo.shared.game.command.GameCommand
import eventDemo.shared.game.notification.Notification
import eventDemo.shared.ids.GameId
import eventDemo.shared.ids.UserId
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
@@ -1,7 +1,7 @@
package eventDemo.contexts.game.application.ports
import eventDemo.contexts.game.domain.events.GameEvent
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.libs.eventSource.eventStore.EventStore
import eventDemo.shared.ids.GameId
interface GameEventStore : EventStore<GameEvent, GameId>
@@ -1,6 +1,6 @@
package eventDemo.domain.event.projection
import eventDemo.contexts.game.infrastructure.persistence.projections.models.GameList
import eventDemo.shared.game.projection.GameList
interface GameListRepository {
fun getList(
@@ -1,6 +1,6 @@
package eventDemo.contexts.game.application.ports
import eventDemo.contexts.game.infrastructure.persistence.projections.models.GameProjection
import eventDemo.libs.bus.Bus
import eventDemo.shared.game.projection.GameProjection
interface GameProjectionBus : Bus<GameProjection>
@@ -9,7 +9,7 @@ import eventDemo.contexts.game.domain.events.NewPlayerEvent
import eventDemo.contexts.game.domain.events.PlayerHaveDrawCardEvent
import eventDemo.contexts.game.domain.events.PlayerReadyEvent
import eventDemo.contexts.game.domain.events.PlayerWinEvent
import eventDemo.contexts.game.infrastructure.persistence.projections.models.GameList
import eventDemo.shared.game.projection.GameList
fun GameList.applyEvent(event: GameEvent): GameList =
when (event) {
@@ -1,15 +1,15 @@
package eventDemo.contexts.game.domain.events
import eventDemo.contexts.game.domain.game.Card
import eventDemo.contexts.game.domain.game.Card.Color
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.domain.game.Player
import eventDemo.contexts.game.infrastructure.persistence.serializers.EventIdSerializer
import eventDemo.libs.eventSource.EventId
import eventDemo.shared.game.Card
import eventDemo.shared.game.Card.Color
import eventDemo.shared.game.Player
import eventDemo.shared.ids.EventId
import eventDemo.shared.ids.GameId
import eventDemo.shared.serializers.EventIdSerializer
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
import java.util.UUID
import kotlin.uuid.Uuid
/**
* An [GameEvent] to represent a played card.
@@ -24,7 +24,7 @@ data class CardIsPlayedEvent(
) : GameEvent,
PlayerActionEvent {
@Serializable(with = EventIdSerializer::class)
override val eventId: EventId = EventId(UUID.randomUUID())
override val eventId: EventId = EventId(Uuid.random())
override val createdAt: Instant = Clock.System.now()
val theColorCard get() = if (card is Card.CardWithColor) card.color else chosenColor
@@ -1,14 +1,14 @@
package eventDemo.contexts.game.domain.events
import eventDemo.contexts.game.domain.game.DiscardPile
import eventDemo.contexts.game.domain.game.DrawPile
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.infrastructure.persistence.serializers.EventIdSerializer
import eventDemo.libs.eventSource.EventId
import eventDemo.shared.game.DiscardPile
import eventDemo.shared.game.DrawPile
import eventDemo.shared.ids.EventId
import eventDemo.shared.ids.GameId
import eventDemo.shared.serializers.EventIdSerializer
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
import java.util.UUID
import kotlin.uuid.Uuid
/**
* When the Pile are shuffled after the draw pille was empty
@@ -21,6 +21,6 @@ class DrawFilledWithDiscardEvent(
override val version: Int,
) : GameEvent {
@Serializable(with = EventIdSerializer::class)
override val eventId: EventId = EventId(UUID.randomUUID())
override val eventId: EventId = EventId(Uuid.random())
override val createdAt: Instant = Clock.System.now()
}
@@ -1,12 +1,12 @@
package eventDemo.contexts.game.domain.events
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.infrastructure.persistence.serializers.EventIdSerializer
import eventDemo.libs.eventSource.EventId
import eventDemo.shared.ids.EventId
import eventDemo.shared.ids.GameId
import eventDemo.shared.serializers.EventIdSerializer
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
import java.util.UUID
import kotlin.uuid.Uuid
/**
* This [GameEvent] is sent when all players are ready.
@@ -17,6 +17,6 @@ data class GameCreatedEvent(
override val version: Int,
) : GameEvent {
@Serializable(with = EventIdSerializer::class)
override val eventId: EventId = EventId(UUID.randomUUID())
override val eventId: EventId = EventId(Uuid.random())
override val createdAt: Instant = Clock.System.now()
}
@@ -1,10 +1,10 @@
package eventDemo.contexts.game.domain.events
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.infrastructure.persistence.serializers.EventIdSerializer
import eventDemo.contexts.game.infrastructure.persistence.serializers.GameIdSerializer
import eventDemo.libs.eventSource.Event
import eventDemo.libs.eventSource.EventId
import eventDemo.shared.ids.EventId
import eventDemo.shared.ids.GameId
import eventDemo.shared.serializers.EventIdSerializer
import eventDemo.shared.serializers.GameIdSerializer
import kotlinx.serialization.Serializable
/**
@@ -1,17 +1,17 @@
package eventDemo.contexts.game.domain.events
import eventDemo.contexts.game.domain.game.DiscardPile
import eventDemo.contexts.game.domain.game.DrawPile
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.domain.game.Player
import eventDemo.contexts.game.domain.game.PlayerHand
import eventDemo.contexts.game.infrastructure.persistence.serializers.EventIdSerializer
import eventDemo.contexts.game.infrastructure.persistence.serializers.PlayerIdSerializer
import eventDemo.libs.eventSource.EventId
import eventDemo.shared.game.DiscardPile
import eventDemo.shared.game.DrawPile
import eventDemo.shared.game.Player
import eventDemo.shared.game.PlayerHand
import eventDemo.shared.ids.EventId
import eventDemo.shared.ids.GameId
import eventDemo.shared.serializers.EventIdSerializer
import eventDemo.shared.serializers.PlayerIdSerializer
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
import java.util.UUID
import kotlin.uuid.Uuid
/**
* This [GameEvent] is sent when all players are ready.
@@ -27,6 +27,6 @@ data class GameStartedEvent(
override val version: Int,
) : GameEvent {
@Serializable(with = EventIdSerializer::class)
override val eventId: EventId = EventId(UUID.randomUUID())
override val eventId: EventId = EventId(Uuid.random())
override val createdAt: Instant = Clock.System.now()
}
@@ -1,13 +1,13 @@
package eventDemo.contexts.game.domain.events
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.domain.game.Player
import eventDemo.contexts.game.infrastructure.persistence.serializers.EventIdSerializer
import eventDemo.libs.eventSource.EventId
import eventDemo.shared.game.Player
import eventDemo.shared.ids.EventId
import eventDemo.shared.ids.GameId
import eventDemo.shared.serializers.EventIdSerializer
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
import java.util.UUID
import kotlin.uuid.Uuid
/**
* An [GameEvent] to represent a new player joining the game.
@@ -22,6 +22,6 @@ data class NewPlayerEvent(
override val playerId: Player.PlayerId get() = player.id
@Serializable(with = EventIdSerializer::class)
override val eventId: EventId = EventId(UUID.randomUUID())
override val eventId: EventId = EventId(Uuid.random())
override val createdAt: Instant = Clock.System.now()
}
@@ -1,6 +1,6 @@
package eventDemo.contexts.game.domain.events
import eventDemo.contexts.game.domain.game.Player
import eventDemo.shared.game.Player
import kotlinx.serialization.Serializable
@Serializable
@@ -1,15 +1,15 @@
package eventDemo.contexts.game.domain.events
import eventDemo.contexts.game.domain.game.Card
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.domain.game.Player
import eventDemo.contexts.game.infrastructure.persistence.serializers.EventIdSerializer
import eventDemo.contexts.game.infrastructure.persistence.serializers.PlayerIdSerializer
import eventDemo.libs.eventSource.EventId
import eventDemo.shared.game.Card
import eventDemo.shared.game.Player
import eventDemo.shared.ids.EventId
import eventDemo.shared.ids.GameId
import eventDemo.shared.serializers.EventIdSerializer
import eventDemo.shared.serializers.PlayerIdSerializer
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
import java.util.UUID
import kotlin.uuid.Uuid
/**
* This [GameEvent] is sent when a player can play.
@@ -24,6 +24,6 @@ data class PlayerHaveDrawCardEvent(
) : GameEvent,
PlayerActionEvent {
@Serializable(with = EventIdSerializer::class)
override val eventId: EventId = EventId(UUID.randomUUID())
override val eventId: EventId = EventId(Uuid.random())
override val createdAt: Instant = Clock.System.now()
}
@@ -1,14 +1,14 @@
package eventDemo.contexts.game.domain.events
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.domain.game.Player
import eventDemo.contexts.game.infrastructure.persistence.serializers.EventIdSerializer
import eventDemo.contexts.game.infrastructure.persistence.serializers.PlayerIdSerializer
import eventDemo.libs.eventSource.EventId
import eventDemo.shared.game.Player
import eventDemo.shared.ids.EventId
import eventDemo.shared.ids.GameId
import eventDemo.shared.serializers.EventIdSerializer
import eventDemo.shared.serializers.PlayerIdSerializer
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
import java.util.UUID
import kotlin.uuid.Uuid
/**
* This [GameEvent] is sent when a player is ready.
@@ -22,6 +22,6 @@ data class PlayerReadyEvent(
) : GameEvent,
PlayerActionEvent {
@Serializable(with = EventIdSerializer::class)
override val eventId: EventId = EventId(UUID.randomUUID())
override val eventId: EventId = EventId(Uuid.random())
override val createdAt: Instant = Clock.System.now()
}
@@ -1,14 +1,14 @@
package eventDemo.contexts.game.domain.events
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.domain.game.Player
import eventDemo.contexts.game.infrastructure.persistence.serializers.EventIdSerializer
import eventDemo.contexts.game.infrastructure.persistence.serializers.PlayerIdSerializer
import eventDemo.libs.eventSource.EventId
import eventDemo.shared.game.Player
import eventDemo.shared.ids.EventId
import eventDemo.shared.ids.GameId
import eventDemo.shared.serializers.EventIdSerializer
import eventDemo.shared.serializers.PlayerIdSerializer
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
import java.util.UUID
import kotlin.uuid.Uuid
/**
* This [GameEvent] is sent when a player is ready.
@@ -22,6 +22,6 @@ data class PlayerWinEvent(
) : GameEvent,
PlayerActionEvent {
@Serializable(with = EventIdSerializer::class)
override val eventId: EventId = EventId(UUID.randomUUID())
override val eventId: EventId = EventId(Uuid.random())
override val createdAt: Instant = Clock.System.now()
}
@@ -1,11 +1,11 @@
package eventDemo.contexts.game.domain.game.errors
import eventDemo.contexts.game.domain.events.GameEvent
import eventDemo.contexts.game.domain.game.Card
import eventDemo.contexts.game.domain.game.Player
import eventDemo.contexts.game.domain.game.PlayerList
import eventDemo.contexts.game.domain.game.gameState.Deck
import eventDemo.contexts.game.domain.game.gameState.Game
import eventDemo.shared.game.Card
import eventDemo.shared.game.Player
import eventDemo.shared.game.PlayerList
abstract class GameException(
message: String,
@@ -9,10 +9,10 @@ import eventDemo.contexts.game.domain.events.NewPlayerEvent
import eventDemo.contexts.game.domain.events.PlayerHaveDrawCardEvent
import eventDemo.contexts.game.domain.events.PlayerReadyEvent
import eventDemo.contexts.game.domain.events.PlayerWinEvent
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.domain.game.PlayerList
import eventDemo.contexts.game.domain.game.errors.GameException
import eventDemo.contexts.game.domain.game.errors.InconsistentEventVersionException
import eventDemo.shared.game.PlayerList
import eventDemo.shared.ids.GameId
sealed interface Game {
val aggregateId: GameId
@@ -4,18 +4,18 @@ import eventDemo.contexts.game.domain.events.GameEvent
import eventDemo.contexts.game.domain.events.GameStartedEvent
import eventDemo.contexts.game.domain.events.NewPlayerEvent
import eventDemo.contexts.game.domain.events.PlayerReadyEvent
import eventDemo.contexts.game.domain.game.Card
import eventDemo.contexts.game.domain.game.DiscardPile
import eventDemo.contexts.game.domain.game.DrawPile
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.domain.game.Player
import eventDemo.contexts.game.domain.game.PlayerHand
import eventDemo.contexts.game.domain.game.PlayerList
import eventDemo.contexts.game.domain.game.errors.AllPlayerNotReadyException
import eventDemo.contexts.game.domain.game.errors.DeckMissingCardsException
import eventDemo.contexts.game.domain.game.errors.NeedMorePlayersToStartGameException
import eventDemo.contexts.game.domain.game.errors.ThePlayerIsNotInTheGameException
import eventDemo.sharedKernel.UserId
import eventDemo.shared.game.Card
import eventDemo.shared.game.DiscardPile
import eventDemo.shared.game.DrawPile
import eventDemo.shared.game.Player
import eventDemo.shared.game.PlayerHand
import eventDemo.shared.game.PlayerList
import eventDemo.shared.ids.GameId
import eventDemo.shared.ids.UserId
data class GameCreated(
override val aggregateId: GameId,
@@ -1,9 +1,9 @@
package eventDemo.contexts.game.domain.game.gameState
import eventDemo.contexts.game.domain.events.GameEvent
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.domain.game.Player
import eventDemo.contexts.game.domain.game.PlayerList
import eventDemo.shared.game.Player
import eventDemo.shared.game.PlayerList
import eventDemo.shared.ids.GameId
data class GameEnded(
override val aggregateId: GameId,
@@ -2,8 +2,8 @@ package eventDemo.contexts.game.domain.game.gameState
import eventDemo.contexts.game.domain.events.GameCreatedEvent
import eventDemo.contexts.game.domain.events.GameEvent
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.domain.game.PlayerList
import eventDemo.shared.game.PlayerList
import eventDemo.shared.ids.GameId
data class GameInit(
override val aggregateId: GameId,
@@ -6,13 +6,6 @@ import eventDemo.contexts.game.domain.events.GameEvent
import eventDemo.contexts.game.domain.events.PlayerActionEvent
import eventDemo.contexts.game.domain.events.PlayerHaveDrawCardEvent
import eventDemo.contexts.game.domain.events.PlayerWinEvent
import eventDemo.contexts.game.domain.game.Card
import eventDemo.contexts.game.domain.game.Card.Color
import eventDemo.contexts.game.domain.game.DiscardPile
import eventDemo.contexts.game.domain.game.DrawPile
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.domain.game.Player
import eventDemo.contexts.game.domain.game.PlayerList
import eventDemo.contexts.game.domain.game.errors.InconsistentGameException
import eventDemo.contexts.game.domain.game.errors.ItsNotTheTurnException
import eventDemo.contexts.game.domain.game.errors.TheCardHasNoColorException
@@ -22,6 +15,13 @@ import eventDemo.contexts.game.domain.game.errors.ThePlayerHasRemainingCardsExce
import eventDemo.contexts.game.domain.game.errors.ThePlayerIsNotInTheGameException
import eventDemo.contexts.game.domain.game.errors.ThePlayerMustPlayACardException
import eventDemo.contexts.game.domain.game.gameState.Game.Direction
import eventDemo.shared.game.Card
import eventDemo.shared.game.Card.Color
import eventDemo.shared.game.DiscardPile
import eventDemo.shared.game.DrawPile
import eventDemo.shared.game.Player
import eventDemo.shared.game.PlayerList
import eventDemo.shared.ids.GameId
fun PlayerList.nextPlayerTurn(
lastPlayerId: Player.PlayerId,
@@ -1,5 +1,6 @@
package eventDemo.contexts.game.infrastructure.configuration.ktor
import eventDemo.shared.http.HttpErrorBadRequest
import io.ktor.http.HttpHeaders
import io.ktor.http.HttpMethod
import io.ktor.http.HttpStatusCode
@@ -10,7 +11,6 @@ import io.ktor.server.plugins.cors.routing.CORS
import io.ktor.server.plugins.statuspages.StatusPages
import io.ktor.server.resources.Resources
import io.ktor.server.response.respondText
import kotlinx.serialization.Serializable
fun Application.configureHttpRouting() {
install(CORS) {
@@ -38,17 +38,3 @@ fun Application.configureHttpRouting() {
class BadRequestException(
val httpError: HttpErrorBadRequest,
) : Exception()
@Serializable
class HttpErrorBadRequest(
val title: String = HttpStatusCode.BadRequest.description,
val invalidParams: List<InvalidParam> = emptyList(),
) {
val statusCode: Int = HttpStatusCode.BadRequest.value
@Serializable
data class InvalidParam(
val name: String,
val reason: String,
)
}
@@ -1,21 +1,21 @@
package eventDemo.contexts.game.infrastructure.configuration.ktor
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.domain.game.Player
import eventDemo.contexts.game.infrastructure.persistence.serializers.CommandIdSerializer
import eventDemo.contexts.game.infrastructure.persistence.serializers.EventIdSerializer
import eventDemo.contexts.game.infrastructure.persistence.serializers.GameIdSerializer
import eventDemo.contexts.game.infrastructure.persistence.serializers.PlayerIdSerializer
import eventDemo.libs.command.CommandId
import eventDemo.libs.eventSource.EventId
import eventDemo.libs.serializer.UUIDSerializer
import eventDemo.shared.game.Player
import eventDemo.shared.ids.CommandId
import eventDemo.shared.ids.EventId
import eventDemo.shared.ids.GameId
import eventDemo.shared.serializers.CommandIdSerializer
import eventDemo.shared.serializers.EventIdSerializer
import eventDemo.shared.serializers.GameIdSerializer
import eventDemo.shared.serializers.PlayerIdSerializer
import eventDemo.shared.serializers.UUIDSerializer
import io.ktor.serialization.kotlinx.json.json
import io.ktor.server.application.Application
import io.ktor.server.application.install
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import java.util.UUID
import kotlin.uuid.Uuid
fun Application.configureSerialization() {
install(ContentNegotiation) {
@@ -29,7 +29,7 @@ fun defaultJsonSerializer(): Json =
Json {
serializersModule =
SerializersModule {
contextual(UUID::class) { UUIDSerializer }
contextual(Uuid::class) { UUIDSerializer }
contextual(GameId::class) { GameIdSerializer }
contextual(EventId::class) { EventIdSerializer }
contextual(CommandId::class) { CommandIdSerializer }
@@ -2,9 +2,9 @@ package eventDemo.contexts.game.infrastructure.persistence.eventStore
import eventDemo.contexts.game.application.ports.GameEventStore
import eventDemo.contexts.game.domain.events.GameEvent
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.libs.eventSource.eventStore.EventStore
import eventDemo.libs.eventSource.eventStore.EventStoreInMemory
import eventDemo.shared.ids.GameId
/**
* A stream to publish and read the played card event.
@@ -2,9 +2,9 @@ package eventDemo.contexts.game.infrastructure.persistence.eventStore
import eventDemo.contexts.game.application.ports.GameEventStore
import eventDemo.contexts.game.domain.events.GameEvent
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.libs.eventSource.eventStore.EventStore
import eventDemo.libs.eventSource.eventStore.EventStoreInPostgresql
import eventDemo.shared.ids.GameId
import kotlinx.serialization.json.Json
import javax.sql.DataSource
@@ -4,9 +4,9 @@ import eventDemo.contexts.game.application.ports.GameEventBus
import eventDemo.contexts.game.application.ports.GameEventStore
import eventDemo.contexts.game.application.ports.GameProjectionBus
import eventDemo.contexts.game.application.projections.applyEvent
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.infrastructure.persistence.projections.models.GameList
import eventDemo.domain.event.projection.GameListRepository
import eventDemo.shared.game.projection.GameList
import eventDemo.shared.ids.GameId
import io.github.oshai.kotlinlogging.withLoggingContext
/**
@@ -1,9 +1,9 @@
package eventDemo.contexts.game.infrastructure.persistence.projections.bus
import eventDemo.contexts.game.application.ports.GameProjectionBus
import eventDemo.contexts.game.infrastructure.persistence.projections.models.GameProjection
import eventDemo.libs.bus.Bus
import eventDemo.libs.bus.BusInMemory
import eventDemo.shared.game.projection.GameProjection
import java.util.UUID
class GameProjectionBusInMemory :
@@ -2,9 +2,9 @@ package eventDemo.contexts.game.infrastructure.persistence.projections.bus
import com.rabbitmq.client.ConnectionFactory
import eventDemo.contexts.game.application.ports.GameProjectionBus
import eventDemo.contexts.game.infrastructure.persistence.projections.models.GameProjection
import eventDemo.libs.bus.Bus
import eventDemo.libs.bus.BusInRabbitMQ
import eventDemo.shared.game.projection.GameProjection
import kotlinx.serialization.json.Json
import java.util.UUID
@@ -3,8 +3,8 @@ package eventDemo.contexts.game.infrastructure.rest
import eventDemo.contexts.game.application.eventStores.GameRepository
import eventDemo.contexts.game.application.notification.toNotification
import eventDemo.contexts.game.application.ports.GameEventStore
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.contexts.game.infrastructure.persistence.serializers.GameIdSerializer
import eventDemo.shared.ids.GameId
import eventDemo.shared.serializers.GameIdSerializer
import eventDemo.sharedKernel.currentUserId
import io.ktor.http.HttpStatusCode
import io.ktor.resources.Resource
@@ -1,22 +1,22 @@
package eventDemo.contexts.game.infrastructure.websocket
import eventDemo.contexts.game.application.channels.GameChannelsSubscriber
import eventDemo.contexts.game.domain.game.GameId
import eventDemo.libs.helpers.fromFrameChannel
import eventDemo.libs.helpers.toObjectChannel
import eventDemo.shared.ids.GameId
import eventDemo.sharedKernel.currentUserId
import io.ktor.server.auth.authenticate
import io.ktor.server.routing.Route
import io.ktor.server.websocket.webSocket
import kotlinx.coroutines.DelicateCoroutinesApi
import java.util.UUID
import kotlin.uuid.Uuid
@DelicateCoroutinesApi
fun Route.gameWebSocket(channelSubscriber: GameChannelsSubscriber) {
authenticate {
webSocket("/games/{id}") {
channelSubscriber.subscribePlayerToGameChannels(
gameId = GameId(UUID.fromString(call.parameters["id"]!!)),
gameId = GameId(Uuid.parse(call.parameters["id"]!!)),
userId = call.currentUserId,
incomingCommandChannel = toObjectChannel(incoming),
sendNotificationChannel = fromFrameChannel(outgoing),
@@ -1,5 +1,7 @@
package eventDemo.libs.command
import eventDemo.shared.command.Command
import eventDemo.shared.ids.CommandId
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import java.util.concurrent.ConcurrentHashMap
@@ -0,0 +1,16 @@
package eventDemo.libs.eventSource
import eventDemo.shared.ids.AggregateId
import eventDemo.shared.ids.EventId
import kotlinx.datetime.Instant
/**
* The basic interface for an Event
* @see eventDemo.libs.eventSource.eventStore.EventStream
*/
interface Event<ID : AggregateId> {
val eventId: EventId
val aggregateId: ID
val createdAt: Instant
val version: Int
}
@@ -1,7 +1,7 @@
package eventDemo.libs.eventSource.eventStore
import eventDemo.libs.eventSource.AggregateId
import eventDemo.libs.eventSource.Event
import eventDemo.shared.ids.AggregateId
import io.github.oshai.kotlinlogging.withLoggingContext
interface EventStore<E : Event<ID>, ID : AggregateId> {
@@ -1,7 +1,7 @@
package eventDemo.libs.eventSource.eventStore
import eventDemo.libs.eventSource.AggregateId
import eventDemo.libs.eventSource.Event
import eventDemo.shared.ids.AggregateId
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
@@ -1,7 +1,7 @@
package eventDemo.libs.eventSource.eventStore
import eventDemo.libs.eventSource.AggregateId
import eventDemo.libs.eventSource.Event
import eventDemo.shared.ids.AggregateId
import javax.sql.DataSource
class EventStoreInPostgresql<E : Event<ID>, ID : AggregateId>(
@@ -1,7 +1,7 @@
package eventDemo.libs.eventSource.eventStore
import eventDemo.libs.eventSource.AggregateId
import eventDemo.libs.eventSource.Event
import eventDemo.shared.ids.AggregateId
import io.github.oshai.kotlinlogging.withLoggingContext
/**
@@ -1,7 +1,7 @@
package eventDemo.libs.eventSource.eventStore
import eventDemo.libs.eventSource.AggregateId
import eventDemo.libs.eventSource.Event
import eventDemo.shared.ids.AggregateId
import io.github.oshai.kotlinlogging.KotlinLogging
import java.util.Queue
import java.util.concurrent.ConcurrentLinkedQueue
@@ -1,12 +1,13 @@
package eventDemo.libs.eventSource.eventStore
import eventDemo.libs.eventSource.AggregateId
import eventDemo.libs.eventSource.Event
import eventDemo.shared.ids.AggregateId
import io.github.oshai.kotlinlogging.KotlinLogging
import io.github.oshai.kotlinlogging.withLoggingContext
import org.postgresql.util.PGobject
import org.postgresql.util.PSQLException
import javax.sql.DataSource
import kotlin.uuid.toJavaUuid
/**
* An In-Memory implementation of an event stream.
@@ -39,8 +40,8 @@ class EventStreamInPostgresql<E : Event<ID>, ID : AggregateId>(
on conflict (id) do nothing
""".trimIndent(),
).use {
it.setObject(1, event.eventId.id)
it.setObject(2, event.aggregateId.id)
it.setObject(1, event.eventId.id.toJavaUuid())
it.setObject(2, event.aggregateId.id.toJavaUuid())
it.setInt(3, event.version)
it.setObject(4, PGJsonb(objectToString(event)))
it.executeUpdate()
@@ -69,7 +70,7 @@ class EventStreamInPostgresql<E : Event<ID>, ID : AggregateId>(
order by version asc
""".trimIndent(),
).use {
it.setObject(1, aggregateId.id)
it.setObject(1, aggregateId.id.toJavaUuid())
it.executeQuery().use { resultSet ->
buildSet {
while (resultSet.next()) {
@@ -95,7 +96,7 @@ class EventStreamInPostgresql<E : Event<ID>, ID : AggregateId>(
order by version asc
""".trimIndent(),
).use {
it.setObject(1, aggregateId.id)
it.setObject(1, aggregateId.id.toJavaUuid())
it.executeQuery().use { resultSet ->
resultSet.next()
}
@@ -116,7 +117,7 @@ class EventStreamInPostgresql<E : Event<ID>, ID : AggregateId>(
).use { stmt ->
stmt.setInt(1, version.first)
stmt.setInt(2, version.last)
stmt.setObject(3, aggregateId.id)
stmt.setObject(3, aggregateId.id.toJavaUuid())
stmt.executeQuery().use { resultSet ->
buildSet {
while (resultSet.next()) {
@@ -1,12 +1,13 @@
package eventDemo.sharedKernel
import eventDemo.shared.ids.UserId
import io.ktor.server.application.ApplicationCall
import io.ktor.server.auth.jwt.JWTPrincipal
import io.ktor.server.auth.principal
import java.util.UUID
import kotlin.uuid.Uuid
internal val ApplicationCall.currentUserId: UserId
get() =
principal<JWTPrincipal>()!!.run {
UserId(UUID.fromString(payload.getClaim("userid").asString()))
UserId(Uuid.parse(payload.getClaim("userid").asString()))
}

Some files were not shown because too many files have changed in this diff Show More