-
-
Notifications
You must be signed in to change notification settings - Fork 755
Kotlin DSL
Atmosphere 4.0 includes an optional atmosphere-kotlin module that provides an idiomatic Kotlin DSL for building AtmosphereHandler instances and coroutine extensions for non-blocking broadcast and write operations.
<dependency>
<groupId>org.atmosphere</groupId>
<artifactId>atmosphere-kotlin</artifactId>
<version>4.0.1</version>
</dependency>The atmosphere { } builder creates an AtmosphereHandler with lambda callbacks instead of verbose anonymous classes:
import org.atmosphere.kotlin.atmosphere
val handler = atmosphere {
onConnect { resource ->
println("${resource.uuid()} connected via ${resource.transport()}")
resource.broadcaster.broadcast("${resource.uuid()} joined")
}
onMessage { resource, message ->
resource.broadcaster.broadcast(message)
}
onDisconnect { resource ->
resource.broadcaster.broadcast("${resource.uuid()} left")
}
onTimeout { resource ->
println("${resource.uuid()} timed out")
}
}
// Register with the framework
framework.addAtmosphereHandler("/chat", handler)| Callback | When it fires |
|---|---|
onConnect |
Client connects (GET request, resource is suspended) |
onMessage |
Message received (POST request, body parsed as String) |
onDisconnect |
Client disconnects or connection closed |
onTimeout |
Resource times out |
onResume |
Resource is resumed |
All callbacks are optional — only implement what you need.
The module provides suspending extension functions that bridge Atmosphere's blocking Future.get() calls into Kotlin structured concurrency:
import org.atmosphere.kotlin.broadcastSuspend
import org.atmosphere.kotlin.writeSuspendSuspends until broadcast delivery completes:
suspend fun handleMessage(broadcaster: Broadcaster, message: String) {
broadcaster.broadcastSuspend(message)
println("Delivered to all connected clients")
}Targeted broadcast to a specific resource:
suspend fun directMessage(broadcaster: Broadcaster, resource: AtmosphereResource, message: String) {
broadcaster.broadcastSuspend(message, resource)
}Write directly to a resource (String or ByteArray):
suspend fun respond(resource: AtmosphereResource) {
resource.writeSuspend("Hello from a coroutine")
resource.writeSuspend(byteArrayOf(0x01, 0x02))
}All extensions use withContext(Dispatchers.IO) internally to avoid blocking the caller's coroutine dispatcher.
Use the DSL to programmatically register handlers in a Spring Boot application:
@Configuration
class AtmosphereConfig {
@Bean
fun customizeFramework(): AtmosphereFrameworkCustomizer {
return AtmosphereFrameworkCustomizer { framework ->
framework.addAtmosphereHandler("/notifications", atmosphere {
onConnect { resource ->
resource.suspend()
}
onMessage { resource, message ->
resource.broadcaster.broadcast(message)
}
})
}
}
}Note: For most use cases, the annotation-driven approach with
@ManagedServiceor@RoomServiceis simpler. The Kotlin DSL is best for dynamic handler registration, testing, or when you prefer a programmatic style over annotations.
- Understanding @ManagedService — annotation-driven endpoints (Java or Kotlin)
- Understanding @RoomService — room-aware endpoints
- AI / LLM Streaming — stream AI responses with Kotlin and Embabel