Skip to content

Commit 5ac97a4

Browse files
committed
chore: ktor plugin and misc refactorings
1 parent f374b8b commit 5ac97a4

File tree

13 files changed

+172
-88
lines changed

13 files changed

+172
-88
lines changed

backend/jvm/src/main/kotlin/dev/suresh/App.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import dev.suresh.di.configureDI
55
import dev.suresh.plugins.*
66
import dev.suresh.routes.*
77
import io.ktor.server.application.*
8-
import io.ktor.server.jetty.jakarta.EngineMain
8+
import io.ktor.server.jetty.jakarta.*
99
import io.ktor.server.routing.*
1010
import io.ktor.util.logging.*
1111
import kotlin.io.path.Path

backend/jvm/src/main/kotlin/dev/suresh/plugins/Http.kt

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ import io.ktor.server.request.*
2121
import io.ktor.server.resources.*
2222
import io.ktor.server.response.*
2323
import io.ktor.server.routing.*
24+
import io.ktor.server.servlet.jakarta.*
2425
import io.ktor.server.sessions.*
2526
import io.ktor.server.sse.*
2627
import io.ktor.server.websocket.*
28+
import javax.net.ssl.SSLSession
2729
import kotlin.concurrent.atomics.AtomicLong
2830
import kotlin.time.Duration
2931
import kotlin.time.Duration.Companion.seconds
@@ -126,7 +128,15 @@ fun Application.configureHTTP() {
126128
mdc("remoteHost") { call -> call.request.origin.remoteHost }
127129
// callIdMdc(TRACE_ID)
128130

129-
// Enable logging for API routes only
131+
// format { call ->
132+
// val status = call.response.status() ?: OK
133+
// val method = call.request.httpMethod.value
134+
// val path = call.request.path()
135+
// val took = call.processingTimeMillis()
136+
// val remote = call.request.origin.remoteHost
137+
// "[$remote] $status: $method $path (${took}ms)"
138+
// }
139+
130140
filter { it.isApi }
131141
}
132142

@@ -141,9 +151,9 @@ fun Application.configureHTTP() {
141151
}
142152

143153
fun Application.configureInterceptors() {
144-
intercept(ApplicationCallPipeline.Plugins) {
145-
println("Request: ${call.request.uri}")
146-
if (call.request.headers["Custom-Header"] == "Test") {
154+
intercept(ApplicationCallPipeline.Call) {
155+
println("[${call.request.origin.remoteHost}] --> ${call.request.uri}")
156+
if (call.request.headers["X-Custom"] == "Test") {
147157
call.respond(HttpStatusCode.Forbidden)
148158
finish()
149159
}
@@ -153,12 +163,15 @@ fun Application.configureInterceptors() {
153163
val ApplicationCall.debug
154164
get() = request.queryParameters.contains("debug")
155165

166+
val ApplicationCall.sslSession
167+
get() = request.servletRequestAttributes["jakarta.servlet.request.ssl_session"] as? SSLSession
168+
156169
val ApplicationCall.isApi
157170
get() = run {
158171
val path = request.path()
159172
when {
160173
path.contains("/swagger") -> false
161-
path.startsWith("/api/") -> true
174+
path.startsWith("/") -> true
162175
else -> false
163176
}
164177
}

backend/jvm/src/main/kotlin/dev/suresh/plugins/OTel.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ fun Application.configureOTel() {
1919
val isAgentActive = globalOtel !== OpenTelemetry.noop()
2020
when (isAgentActive) {
2121
true -> log.info("\uD83D\uDFE2 OTel Java agent is active")
22-
else -> log.warn("\uD83D\uDFE1 OTel Java agent is inactive!!")
22+
else -> log.warn("\uD83D\uDFE1 OTel Java agent is inactive")
2323
}
2424

25-
install(OTelExtnPlugin) { enabled = true }
25+
install(OTelExtnPlugin)
2626
// otelSdk.shutdown().join(10, TimeUnit.SECONDS);
2727
}
2828

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package dev.suresh.plugins.custom
2+
3+
import io.ktor.server.application.*
4+
import io.ktor.server.auth.*
5+
import io.ktor.server.response.*
6+
7+
class AuthzPluginConfig {
8+
var enabled: Boolean = false
9+
var roles: Set<String> = emptySet()
10+
lateinit var getRole: (userName: String?) -> String
11+
}
12+
13+
val AuthzPlugin =
14+
createRouteScopedPlugin(name = "AuthzPlugin", createConfiguration = ::AuthzPluginConfig) {
15+
if (!pluginConfig.enabled) return@createRouteScopedPlugin
16+
application.log.info("\uD83E\uDDE9 AuthzPlugin is installed")
17+
18+
on(AuthenticationChecked) { call ->
19+
val userName = call.principal<UserIdPrincipal>()?.name
20+
val userRole = pluginConfig.getRole(userName)
21+
if (userRole !in pluginConfig.roles) {
22+
call.respondText(
23+
"You are not allowed to visit this page",
24+
status = Forbidden,
25+
)
26+
}
27+
}
28+
}

backend/jvm/src/main/kotlin/dev/suresh/plugins/custom/Plugins.kt renamed to backend/jvm/src/main/kotlin/dev/suresh/plugins/custom/OTelExtnPlugin.kt

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,34 @@ package dev.suresh.plugins.custom
22

33
import dev.suresh.plugins.isApi
44
import io.ktor.server.application.*
5+
import io.ktor.server.config.*
56
import io.ktor.util.*
67
import io.opentelemetry.api.trace.Span
8+
import kotlinx.serialization.Serializable
9+
10+
@Serializable
11+
data class OTelExtnPluginConfig(
12+
val enabled: Boolean = false,
13+
val traceIdHeader: String = "X-TraceId",
14+
)
715

816
/**
917
* A custom ktor plugin to automatically add OpenTelemetry trace id to response headers for API
1018
* endpoints.
1119
*/
1220
val OTelExtnPlugin =
13-
createApplicationPlugin(name = "OTelExtnPlugin", createConfiguration = ::OTelExtnPluginConfig) {
21+
createApplicationPlugin(name = "OTelExtnPlugin") {
22+
val config: OTelExtnPluginConfig = application.property("plugins.otel-extn")
23+
if (!config.enabled) return@createApplicationPlugin
24+
application.log.info("\uD83E\uDDE9 OTelExtnPlugin is installed")
25+
1426
val onCallTimeKey = AttributeKey<Long>("onCallTimeKey")
1527
onCall { call ->
1628
val onCallTime = System.currentTimeMillis()
1729
call.attributes.put(onCallTimeKey, onCallTime)
18-
19-
if (pluginConfig.enabled && call.isApi) {
30+
if (call.isApi) {
2031
Span.current()?.let { span ->
21-
call.response.headers.append(pluginConfig.traceIdHeader, span.spanContext.traceId)
32+
call.response.headers.append(config.traceIdHeader, span.spanContext.traceId)
2233
// span.setAttribute("custom-attribute", "TestPlugin")
2334
// span.addEvent("TestPluginEvent")
2435
}
@@ -48,8 +59,3 @@ val OTelExtnPlugin =
4859
// }
4960
// }
5061
}
51-
52-
class OTelExtnPluginConfig {
53-
var enabled: Boolean = false
54-
var traceIdHeader: String = "X-TraceId"
55-
}

backend/jvm/src/main/kotlin/dev/suresh/routes/Service.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ import dev.suresh.JFR
44
import dev.suresh.http.*
55
import dev.suresh.lang.*
66
import dev.suresh.log.RespLogger
7+
import dev.suresh.plugins.custom.AuthzPlugin
78
import dev.suresh.plugins.custom.CookieSession
89
import dev.suresh.wasm.wasm
910
import io.github.oshai.kotlinlogging.KLogger
1011
import io.github.oshai.kotlinlogging.KotlinLogging
1112
import io.ktor.http.*
1213
import io.ktor.server.application.*
14+
import io.ktor.server.auth.UserIdPrincipal
15+
import io.ktor.server.auth.principal
1316
import io.ktor.server.http.content.*
1417
import io.ktor.server.plugins.csrf.*
1518
import io.ktor.server.response.*
@@ -109,6 +112,15 @@ fun Routing.services() {
109112
println(call.isDecompressionSuppressed)
110113
println(call.isCompressionSuppressed) // true
111114
}
115+
116+
route("/authz") {
117+
install(AuthzPlugin) {
118+
enabled = true
119+
roles = setOf("admin")
120+
getRole = { it ?: "admin" }
121+
}
122+
get { call.respondText("Hello, ${call.principal<UserIdPrincipal>()?.name}!") }
123+
}
112124
}
113125

114126
@WithSpan suspend fun mediaApiCall() = MediaApiClient().images().size

backend/jvm/src/main/resources/application.conf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,11 @@ app {
5454
maxDelay = PT5S
5555
}
5656
}
57+
}
58+
59+
plugins {
60+
otel-extn {
61+
enabled = true
62+
traceIdHeader = "X-TraceId"
63+
}
5764
}

compose/cmp/build.gradle.kts

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
1-
@file:OptIn(ExperimentalComposeLibrary::class)
21
@file:Suppress("UnstableApiUsage")
32

43
import common.*
54
import common.Platform
65
import java.time.Year
76
import kotlin.io.path.listDirectoryEntries
8-
import org.jetbrains.compose.ExperimentalComposeLibrary
97
import org.jetbrains.compose.desktop.application.dsl.TargetFormat.*
108
import org.jetbrains.compose.desktop.application.tasks.AbstractJPackageTask
119

1210
plugins {
1311
id("dev.suresh.plugin.kotlin.mpp")
1412
alias(libs.plugins.kotlin.compose.compiler)
1513
alias(libs.plugins.jetbrains.compose)
16-
alias(libs.plugins.jetbrains.compose.hotreload)
1714
// alias(libs.plugins.detekt)
1815
id("dev.suresh.plugin.publishing")
1916
}
@@ -27,30 +24,26 @@ kotlin {
2724
sourceSets {
2825
commonMain.dependencies {
2926
implementation(projects.shared)
30-
implementation(compose.runtime)
31-
implementation(compose.foundation)
32-
implementation(compose.material3)
33-
implementation(compose.ui)
34-
implementation(compose.components.resources)
35-
implementation(compose.preview)
36-
27+
implementation(libs.compose.material3)
3728
implementation(libs.compose.nav)
3829
implementation(libs.compose.lifecycle.viewmodel)
3930
implementation(libs.compose.material3.adaptive)
4031
implementation(libs.compose.material3.adaptive.layout)
4132
implementation(libs.compose.material3.adaptive.nav)
4233
implementation(libs.compose.material.icons.core)
4334
implementation(libs.compose.kottie)
35+
implementation(libs.compose.resources)
36+
implementation(libs.compose.ui.toolingpreview)
4437

4538
// implementation(compose.materialIconsExtended)
4639
// project.dependencies.detektPlugins(libs.detekt.compose.rules)
4740
}
4841

49-
commonTest.dependencies { implementation(compose.uiTest) }
42+
commonTest.dependencies { implementation(libs.compose.ui.test) }
5043

5144
jvmMain.dependencies {
5245
implementation(compose.desktop.currentOs)
53-
implementation(compose.desktop.components.animatedImage)
46+
implementation(libs.compose.animatedimage)
5447
implementation(libs.kotlinx.coroutines.swing)
5548
implementation(libs.slf4j.simple)
5649
}

compose/cmp/src/commonMain/kotlin/ui/home/HomeScreen.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ fun Home(navToFile: () -> Unit, navToImage: () -> Unit) {
7171

7272
append("Compose Multiplatform : ")
7373
withStyle(style = SpanStyle(color = Color.Blue, fontWeight = FontWeight.Bold)) {
74-
append(BuildConfig.jetbrainsCompose)
74+
append(BuildConfig.compose)
7575
}
7676
}
7777
showImage = !showImage

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx6g
33
org.gradle.parallel=true
44
org.gradle.caching=true
55
org.gradle.daemon=true
6-
org.gradle.configureondemand=true
6+
org.gradle.configureondemand=false
77
org.gradle.configuration-cache=true
88
org.gradle.configuration-cache.parallel=true
99
org.gradle.configuration-cache.problems=warn

0 commit comments

Comments
 (0)