diff --git a/books/build.gradle.kts b/books/build.gradle.kts index 6f57a11..87e94e8 100644 --- a/books/build.gradle.kts +++ b/books/build.gradle.kts @@ -32,7 +32,7 @@ kotlin { implementation(libs.ktor.client) implementation(libs.ktor.clientCio) implementation(libs.ktor.clientAuth) - implementation(libs.ktor.clientLogging) +// implementation(libs.ktor.clientLogging) implementation(libs.ktor.clientContentNegotiation) implementation(libs.ktor.serializationJson) implementation(libs.ktor.serverCore) @@ -43,6 +43,8 @@ kotlin { implementation(libs.koin.compose) implementation(libs.koin.compose.viewmodel) // implementation(libs.koin.compose.viewmodel.navigation) + implementation(libs.kotlin.logging) + implementation(libs.logback) implementation(projects.shared) } // commonTest.dependencies { @@ -51,10 +53,7 @@ kotlin { jvmMain.dependencies { implementation(compose.desktop.currentOs) implementation(libs.kotlinx.coroutinesSwing) - implementation(libs.ktor.clientJava) // ?? -// implementation(libs.ktor.serverCio) -// implementation(libs.ktor.serverCore) -// implementation(libs.ktor.serverNetty) +// implementation(libs.ktor.clientJava) // ?? implementation(libs.ktor.serverAuthJwt) // nicht f. js, wasmJs } // wasmJsMain.dependencies { diff --git a/books/buildnumber.properties b/books/buildnumber.properties index 67a0475..92cb628 100644 --- a/books/buildnumber.properties +++ b/books/buildnumber.properties @@ -1,3 +1,3 @@ #auto generated -#Fri Feb 06 16:36:58 CET 2026 -build.number=212 +#Fri Feb 06 23:31:36 CET 2026 +build.number=221 diff --git a/books/src/commonMain/kotlin/net/keinekekse/app/App.kt b/books/src/commonMain/kotlin/net/keinekekse/app/App.kt index deddd57..4bdb836 100644 --- a/books/src/commonMain/kotlin/net/keinekekse/app/App.kt +++ b/books/src/commonMain/kotlin/net/keinekekse/app/App.kt @@ -14,6 +14,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview +import io.github.oshai.kotlinlogging.KotlinLogging import io.ktor.client.* import io.ktor.client.request.* import io.ktor.client.statement.* @@ -27,6 +28,8 @@ import org.jetbrains.compose.resources.painterResource import org.koin.compose.koinInject import org.koin.core.annotation.Single +private val logger = KotlinLogging.logger {} + @Composable @Preview fun App() { @@ -52,7 +55,7 @@ fun App() { } Button(onClick = { CoroutineScope(Dispatchers.Default).launch { - println("requesting '/test'") + logger.debug { "requesting '/test'" } test.request("/test") } }) { @@ -77,10 +80,11 @@ class TestAuth(val httpClient: HttpClient) { private val srv = "https://kas.keinekekse.net/" suspend fun request(url: String) { - println("connecting") + logger.debug { "connecting" } val response = httpClient.get(srv + url) - println("call to $url") - println(response.status) - println(response.bodyAsText()) + val body = response.bodyAsText() + logger.debug { "call to $url" } + logger.debug { response.status } + logger.debug { body } } } diff --git a/books/src/commonMain/kotlin/net/keinekekse/app/books/Version.kt b/books/src/commonMain/kotlin/net/keinekekse/app/books/Version.kt index 0c5d63b..2e0a926 100644 --- a/books/src/commonMain/kotlin/net/keinekekse/app/books/Version.kt +++ b/books/src/commonMain/kotlin/net/keinekekse/app/books/Version.kt @@ -4,13 +4,13 @@ import net.keinekekse.version.Version object VERSION: Version { override val version = "1.0.0" - override val fullVersion = "1.0.0+build.212" + override val fullVersion = "1.0.0+build.221" override val major = 1 override val minor = 0 override val patch = 0 override val preRelease = "" - override val buildMetadata = "build.212" - override val buildDate = "2026-02-06T15:36:58.060625Z" + override val buildMetadata = "build.221" + override val buildDate = "2026-02-06T22:31:36.863331Z" override val displayName = "Books App" override val copyright = "Copyright (c) 2026 Hartmut Bauer" override val name = "books" diff --git a/books/src/commonMain/resources/logback.xml b/books/src/commonMain/resources/logback.xml new file mode 100644 index 0000000..2f06544 --- /dev/null +++ b/books/src/commonMain/resources/logback.xml @@ -0,0 +1,12 @@ + + + + %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + diff --git a/books/src/jvmMain/kotlin/net/keinekekse/app/auth/AuthModule.kt b/books/src/jvmMain/kotlin/net/keinekekse/app/auth/AuthModule.kt index c6bb65c..1ce6a52 100644 --- a/books/src/jvmMain/kotlin/net/keinekekse/app/auth/AuthModule.kt +++ b/books/src/jvmMain/kotlin/net/keinekekse/app/auth/AuthModule.kt @@ -1,5 +1,6 @@ package net.keinekekse.app.auth +import io.github.oshai.kotlinlogging.KotlinLogging import kotlinx.coroutines.CompletableDeferred import net.keinekekse.app.config.ConfigProperties import org.koin.core.annotation.Single @@ -7,6 +8,8 @@ import java.security.MessageDigest import java.security.SecureRandom import java.util.* +private val logger = KotlinLogging.logger {} + sealed interface AuthResult { class Success : AuthResult diff --git a/books/src/jvmMain/kotlin/net/keinekekse/app/auth/Authenticator.kt b/books/src/jvmMain/kotlin/net/keinekekse/app/auth/Authenticator.kt index d740367..ad2dfc1 100644 --- a/books/src/jvmMain/kotlin/net/keinekekse/app/auth/Authenticator.kt +++ b/books/src/jvmMain/kotlin/net/keinekekse/app/auth/Authenticator.kt @@ -1,6 +1,7 @@ package net.keinekekse.app.auth import com.auth0.jwt.JWT +import io.github.oshai.kotlinlogging.KotlinLogging import io.ktor.client.* import io.ktor.client.call.* import io.ktor.client.plugins.* @@ -27,6 +28,8 @@ import java.net.Socket import java.util.* import kotlin.use +private val logger = KotlinLogging.logger {} + @Single class Authenticator( val tokenService: TokenService, @@ -54,11 +57,11 @@ class Authenticator( val access = JWT.decode(tokens.accessToken) val refresh = JWT.decode(tokens.refreshToken) val now = Date() - println("Now: $now") - println("Token expires at: ${access.expiresAt}") - println("Token is expired: ${access.expiresAt.before(Date())}") - println("Refresh token expires at: ${refresh.expiresAt}") - println("Refresh token is expired: ${refresh.expiresAt.before(Date())}") + logger.debug { "Now: $now" } + logger.debug { "Token expires at: ${access.expiresAt}" } + logger.debug { "Token is expired: ${access.expiresAt.before(Date())}" } + logger.debug { "Refresh token expires at: ${refresh.expiresAt}" } + logger.debug { "Refresh token is expired: ${refresh.expiresAt.before(Date())}" } if (access.expiresAt.before(now)) { // access_token ungültig if (refresh.expiresAt.before(now)) { @@ -66,10 +69,10 @@ class Authenticator( return doAuthentication() } else { val result = requestRefreshToken(tokens) - if (result != null) { - return AuthResult.Success() + return if (result != null) { + AuthResult.Success() } else { - return doAuthentication() + doAuthentication() } } } else { @@ -145,32 +148,33 @@ class Authenticator( else -> { tokenService.setTokens(null) - println("Error refreshing tokens: ") + logger.debug { "Error refreshing tokens: " } var error = "" var errorDetails = "" when (val err = result.first) { is AuthResult.Fatal -> { - println(err.code) + logger.debug { err.code } error = err.message ?: "" errorDetails = err.details ?: "" } is AuthResult.Error -> { - println(err.code) + logger.debug { err.code } error = err.message ?: "" errorDetails = err.details ?: "" } is AuthResult.Success -> println("Success ???") } - println("Status: ${response.status}") - println("Error: $error") - println("Description: $errorDetails") - if (error == "invalid_grant") { + logger.debug { "Status: ${response.status}" } + logger.debug { "Error: #$error#" } + logger.debug { "Description: $errorDetails" } + return if (error == "invalid_grant") { // session expired || token is invalid - return reAuthenticate() + logger.debug { "Session expired or token invalid. Re-authenticating..." } + reAuthenticate() } else { - return null + null } } } @@ -182,7 +186,7 @@ class Authenticator( Socket(KeycloakConfig.LOCALHOST, port).use { true } } catch (e: Exception) { // Port is closed or unreachable - println("${e.javaClass.simpleName}: ${e.message}") + logger.debug { "${e.javaClass.simpleName}: ${e.message}" } false } @@ -341,7 +345,6 @@ class Authenticator( data class TokenErrorResponse( @SerialName("error") val error: String, @SerialName("error_description") val errorDescription: String?, - @SerialName("session_state") val sessionState: String?, ) private suspend fun requestTokens(config: AuthRun, authCode: String?): AuthResult { diff --git a/books/src/jvmMain/kotlin/net/keinekekse/app/main.kt b/books/src/jvmMain/kotlin/net/keinekekse/app/main.kt index 0932d52..3981196 100644 --- a/books/src/jvmMain/kotlin/net/keinekekse/app/main.kt +++ b/books/src/jvmMain/kotlin/net/keinekekse/app/main.kt @@ -3,9 +3,12 @@ package net.keinekekse.app //import org.koin.plugin.module.dsl.startKoin import androidx.compose.ui.window.Window import androidx.compose.ui.window.application +import io.github.oshai.kotlinlogging.KotlinLogging import net.keinekekse.app.books.di.KoinApp import org.koin.plugin.module.dsl.startKoin +private val logger = KotlinLogging.logger {} + //@PropertyValue("kc_server") //var keycloakServer: String = "" // @@ -18,7 +21,8 @@ import org.koin.plugin.module.dsl.startKoin fun main() = application { startKoin() - + logger.info { "Koin started" } + logger.debug { "Debugging Koin start" } // val config: ConfigProperties = koinInject() // val settings: Settings = koinInject() diff --git a/books/src/jvmMain/kotlin/net/keinekekse/app/service/HttpClient.kt b/books/src/jvmMain/kotlin/net/keinekekse/app/service/HttpClient.kt index 761c66a..1944c56 100644 --- a/books/src/jvmMain/kotlin/net/keinekekse/app/service/HttpClient.kt +++ b/books/src/jvmMain/kotlin/net/keinekekse/app/service/HttpClient.kt @@ -1,6 +1,7 @@ package net.keinekekse.app.service import com.auth0.jwt.JWT +import io.github.oshai.kotlinlogging.KotlinLogging import io.ktor.client.* import io.ktor.client.plugins.* import io.ktor.client.plugins.auth.* @@ -13,6 +14,8 @@ import net.keinekekse.app.auth.Authenticator import org.koin.core.annotation.Single import java.util.* +private val logger = KotlinLogging.logger {} + @OptIn(ExperimentalSerializationApi::class) @Single fun createHttpClient(authenticator: Authenticator): HttpClient { @@ -20,32 +23,32 @@ fun createHttpClient(authenticator: Authenticator): HttpClient { install(Auth) { bearer { loadTokens { - println("HTTPClient: loadTokens") + logger.debug { "HTTPClient: loadTokens" } // tokenService.getTokens() authenticator.tokenService.getTokens() } refreshTokens { - println("HTTPClient: refreshTokens") + logger.debug { "HTTPClient: refreshTokens" } // val tokens = authenticator.tokenService.getTokens() if (oldTokens != null) { val access = JWT.decode(oldTokens?.accessToken) val refresh = JWT.decode(oldTokens?.refreshToken) val now = Date() - println("Now: $now") - println("Token expires at: ${access.expiresAt}") - println("Token is expired: ${access.expiresAt.before(Date())}") - println("Refresh token expires at: ${refresh.expiresAt}") - println("Refresh token is expired: ${refresh.expiresAt.before(Date())}") + logger.debug { "Now: $now" } + logger.debug { "Token expires at: ${access.expiresAt}" } + logger.debug { "Token is expired: ${access.expiresAt.before(Date())}" } + logger.debug { "Refresh token expires at: ${refresh.expiresAt}" } + logger.debug { "Refresh token is expired: ${refresh.expiresAt.before(Date())}" } if (refresh.expiresAt.before(now)) { - println("refresh token expired - HOW TO authenticate") + logger.debug { "refresh token expired - HOW TO authenticate" } authenticator.reAuthenticate() } else { - println("refresh token valid - request new tokens") + logger.debug { "refresh token valid - request new tokens" } authenticator.requestRefreshToken(oldTokens) } } else { - println("no tokens - authenticate") + logger.debug { "no tokens - authenticate" } authenticator.reAuthenticate() } } @@ -68,9 +71,9 @@ fun createHttpClient(authenticator: Authenticator): HttpClient { } client.plugin(HttpSend).intercept { request -> - println("HTTPClient: intercept ${request.url}") + logger.debug { "HTTPClient: intercept ${request.url}" } val originalCall = execute(request) - println("HTTPClient: response status ${originalCall.response.status}") + logger.debug { "HTTPClient: response status ${originalCall.response.status}" } originalCall // val originalCall = execute(request) // if (originalCall.response.status.value !in 100..399) { diff --git a/books/src/jvmMain/kotlin/net/keinekekse/app/service/TokenService.kt b/books/src/jvmMain/kotlin/net/keinekekse/app/service/TokenService.kt index 3a4a7d6..dacf944 100644 --- a/books/src/jvmMain/kotlin/net/keinekekse/app/service/TokenService.kt +++ b/books/src/jvmMain/kotlin/net/keinekekse/app/service/TokenService.kt @@ -1,8 +1,11 @@ package net.keinekekse.app.service +import io.github.oshai.kotlinlogging.KotlinLogging import io.ktor.client.plugins.auth.providers.* import org.koin.core.annotation.Single +private val logger = KotlinLogging.logger {} + @Single class TokenService { private var tokens: BearerTokens? = null @@ -11,9 +14,9 @@ class TokenService { fun setTokens(tokens: BearerTokens? = null) { this.tokens = tokens - println("set tokens") - println("Access Token: ${tokens?.accessToken}") - println("Refresh Token: ${tokens?.refreshToken}") + logger.debug { "set tokens" } + logger.debug { "Access Token: ${tokens?.accessToken}" } + logger.debug { "Refresh Token: ${tokens?.refreshToken}" } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2dea32f..a6a9ae3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,6 +17,7 @@ koin-bom = "4.2.0-RC1" koin-plugin = "0.3.0" ktor = "3.4.0" logback = "1.5.26" +kotlinLogging = "7.0.14" material3 = "1.10.0-alpha05" settings = "1.3.0" dataStore = "1.2.0" @@ -41,6 +42,7 @@ kotlinx-coroutinesSwing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-s kotlinx-html = { module = "org.jetbrains.kotlinx:kotlinx-html", version.ref = "kotlinx-html" } kotlin-wrappersCss = { module = "org.jetbrains.kotlin-wrappers:kotlin-css-jvm", version.ref = "kotlin-wrappers-css" } logback = { module = "ch.qos.logback:logback-classic", version.ref = "logback" } +kotlin-logging = { module = "io.github.oshai:kotlin-logging", version.ref = "kotlinLogging" } ktor-serverCore = { module = "io.ktor:ktor-server-core", version.ref = "ktor" } ktor-serverNetty = { module = "io.ktor:ktor-server-netty", version.ref = "ktor" } ktor-serverCio = { module = "io.ktor:ktor-server-cio", version.ref = "ktor" } diff --git a/server/build.gradle.kts b/server/build.gradle.kts index 9fc94b7..f92c67f 100644 --- a/server/build.gradle.kts +++ b/server/build.gradle.kts @@ -23,6 +23,7 @@ dependencies { implementation(masterLibs.utilLibrary) // implementation(projects.shared) // err wg. doppelter jar ?? implementation(libs.logback) + implementation(libs.kotlin.logging) implementation(libs.ktor.serverCore) implementation(libs.ktor.serverNetty) implementation(libs.ktor.serverAuth) diff --git a/server/src/main/kotlin/net/keinekekse/app/Application.kt b/server/src/main/kotlin/net/keinekekse/app/Application.kt index 270f51c..06f0483 100644 --- a/server/src/main/kotlin/net/keinekekse/app/Application.kt +++ b/server/src/main/kotlin/net/keinekekse/app/Application.kt @@ -1,14 +1,17 @@ package net.keinekekse.app +import io.github.oshai.kotlinlogging.KotlinLogging import io.ktor.server.application.* import io.ktor.server.engine.* import io.ktor.server.netty.* import net.keinekekse.app.server.VERSION import net.keinekekse.app.server.config.configureSecurity +private val logger = KotlinLogging.logger {} + fun main() { // embeddedServer(Netty, port = SERVER_PORT, host = "0.0.0.0", module = Application::module) - println("**\n** Starting ${VERSION.displayName} - ${VERSION.description} ${VERSION.fullVersion}\n**") + logger.debug { "**\n** Starting ${VERSION.displayName} - ${VERSION.description} ${VERSION.fullVersion}\n**" } embeddedServer(Netty, port = 7770, host = "0.0.0.0", module = Application::module) .start(wait = true) } diff --git a/server/src/main/kotlin/net/keinekekse/app/server/config/security.kt b/server/src/main/kotlin/net/keinekekse/app/server/config/security.kt index 5933573..b3d0fa5 100644 --- a/server/src/main/kotlin/net/keinekekse/app/server/config/security.kt +++ b/server/src/main/kotlin/net/keinekekse/app/server/config/security.kt @@ -1,6 +1,7 @@ package net.keinekekse.app.server.config import com.auth0.jwk.UrlJwkProvider +import io.github.oshai.kotlinlogging.KotlinLogging import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.auth.* @@ -10,6 +11,8 @@ import io.ktor.server.routing.* import net.keinekekse.app.server.VERSION import java.net.URI +private val logger = KotlinLogging.logger {} + fun Application.configureSecurity() { // TODO die Werte müssen aus der Config kommen diff --git a/server/src/main/resources/logback.xml b/server/src/main/resources/logback.xml index 3e11d78..bdbb64e 100644 --- a/server/src/main/resources/logback.xml +++ b/server/src/main/resources/logback.xml @@ -9,4 +9,4 @@ - \ No newline at end of file + diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 4ae0b12..b5f1fc2 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -26,6 +26,7 @@ kotlin { commonMain.dependencies { implementation(libs.bundles.kotlin.compose) implementation(libs.ktor.serializationJson) + implementation(libs.ktor.clientLogging) } jvmMain.dependencies {