-
-
Notifications
You must be signed in to change notification settings - Fork 761
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.writeSuspend
Suspends 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