diff --git a/examples/README.md b/examples/README.md index 85ccb0f..d0d2cb1 100644 --- a/examples/README.md +++ b/examples/README.md @@ -29,3 +29,11 @@ This example uses the plain Java `HttpServer` to serve the front end. ([code](ja ```shell cd ./java-httpserver ; jbang server.kt ; cd .. ``` + +### Ktor + +This example uses the `Ktor` to serve the front end. ([code](ktor/server.kt)) + +```shell +cd ./ktor ; jbang server.kt ; cd .. +``` diff --git a/examples/java-httpserver/server.kt b/examples/java-httpserver/server.kt index 34b3574..dd4e68e 100755 --- a/examples/java-httpserver/server.kt +++ b/examples/java-httpserver/server.kt @@ -48,6 +48,9 @@ fun server( this@sseContext.patchElements( """${event}""" ) + if (event == 3) { + this@sseContext.executeScript("""alert('Thanks for trying Datastar!')""") + } } } } diff --git a/examples/ktor/server.kt b/examples/ktor/server.kt new file mode 100755 index 0000000..f6fb683 --- /dev/null +++ b/examples/ktor/server.kt @@ -0,0 +1,97 @@ +import dev.datastar.kotlin.sdk.Response +import dev.datastar.kotlin.sdk.ServerSentEventGenerator +import io.ktor.http.ContentType +import io.ktor.http.HttpStatusCode.Companion.NoContent +import io.ktor.http.HttpStatusCode.Companion.OK +import io.ktor.server.engine.embeddedServer +import io.ktor.server.netty.Netty +import io.ktor.server.response.respondBytes +import io.ktor.server.response.respondTextWriter +import io.ktor.server.routing.get +import io.ktor.server.routing.post +import io.ktor.server.routing.routing +import kotlinx.coroutines.flow.MutableStateFlow +import java.io.File +import java.io.Writer + +///usr/bin/env jbang "$0" "$@" ; exit $? +//JAVA 21 +//KOTLIN 2.2.0 +//DEPS dev.cloudgt.datastar:kotlin-sdk:0.1.0 +//DEPS io.ktor:ktor-server-core-jvm:3.2.3 +//DEPS io.ktor:ktor-server-netty-jvm:3.2.3 + + +fun main() { + server().run { + println("Let's go counting star... http://localhost:8080") + start(wait = true) + } +} + +fun server( + counter: MutableStateFlow = MutableStateFlow(0), +) = embeddedServer(Netty, port = 8080) { + + val counterPage = File( + "../front/counter.html" + ).readBytes() + + routing { + + get("/") { + call.response.headers.append("Content-Type", "text/html") + call.response.status(OK) + call.respondBytes(counterPage) + } + + get("/counter") { + call.respondTextWriter( + status = OK, + contentType = ContentType.Text.EventStream, + ) { + + val response = adaptResponse(this) + val generator = ServerSentEventGenerator(response) + + counter.collect { event -> + generator.patchElements("""${event}""") + + if (event == 3) { + generator.executeScript("""alert('Thanks for trying Datastar!')""") + } + } + + } + } + + post("/increment") { + counter.value++ + call.response.status(NoContent) + } + + post("/decrement") { + counter.value-- + call.response.status(NoContent) + } + + } +} + +private fun adaptResponse(writer: Writer): Response = + object : Response { + override fun sendConnectionHeaders( + status: Int, + headers: Map>, + ) { + // connection is already set up when used + } + + override fun write(text: String) { + writer.write(text) + } + + override fun flush() { + writer.flush() + } + } \ No newline at end of file