Jeżeli potrzebny jest naprawdę totalny minimalizm (obsługa jedynie websocketów, bez klasycznego HTTP) to można użyć czystego Netty (wszystkie Ratpacki czy inne Vertexy się na tym opierają):
import io.netty.bootstrap.ServerBootstrap
import io.netty.channel.ChannelHandler
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.ChannelInitializer
import io.netty.channel.SimpleChannelInboundHandler
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.SocketChannel
import io.netty.channel.socket.nio.NioServerSocketChannel
import io.netty.handler.codec.http.HttpObjectAggregator
import io.netty.handler.codec.http.HttpServerCodec
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler
// connect with ws://localhost:8080/ws
fun main() {
val startTime = System.currentTimeMillis()
ServerBootstrap()
.group(NioEventLoopGroup())
.channel(NioServerSocketChannel::class.java)
.childHandler(object : ChannelInitializer<SocketChannel>() {
override fun initChannel(connection: SocketChannel) {
connection.pipeline()
.addLast(HttpServerCodec())
.addLast(HttpObjectAggregator(Short.MAX_VALUE.toInt()))
.addLast(WebSocketServerProtocolHandler("/ws"))
.addLast(WebsocketRequestHandler)
}
})
.bind(8080)
.sync()
.channel().apply {
println("Startup time: ${System.currentTimeMillis() - startTime}ms")
closeFuture().sync()
}
}
@ChannelHandler.Sharable
object WebsocketRequestHandler : SimpleChannelInboundHandler<TextWebSocketFrame>() {
override fun channelRead0(context: ChannelHandlerContext, frame: TextWebSocketFrame) {
val text = frame.text()
println("Received text: $text")
context.channel()
.writeAndFlush(TextWebSocketFrame("Echo: $text"));
}
}
Wystarczy jedna dependencja:
compile group: 'io.netty', name: 'netty-all', version: '4.1.48.Final'
Żeby zakodzić jednak coś poważniejszego na samym Netty, to próg wejścia rośnie znacząco bo to dość niskopoziomowa biblioteka mimo wszystko.