mirror of
https://github.com/tursom/TursomServer.git
synced 2025-01-29 05:40:18 +08:00
update
This commit is contained in:
parent
7a1371f16c
commit
df633fc80d
@ -18,13 +18,24 @@ import io.netty.handler.codec.http.HttpClientCodec
|
|||||||
import io.netty.handler.codec.http.HttpObjectAggregator
|
import io.netty.handler.codec.http.HttpObjectAggregator
|
||||||
import io.netty.handler.codec.http.websocketx.*
|
import io.netty.handler.codec.http.websocketx.*
|
||||||
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketClientCompressionHandler
|
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketClientCompressionHandler
|
||||||
|
import io.netty.handler.logging.LoggingHandler
|
||||||
import io.netty.handler.ssl.SslContextBuilder
|
import io.netty.handler.ssl.SslContextBuilder
|
||||||
import io.netty.handler.ssl.util.InsecureTrustManagerFactory
|
import io.netty.handler.ssl.util.InsecureTrustManagerFactory
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
|
|
||||||
class WebSocketClient(uri: String, val handler: WebSocketHandler, val autoWrap: Boolean = true) {
|
@Suppress("unused")
|
||||||
private val uri: URI = URI.create(uri)
|
class WebSocketClient(
|
||||||
|
url: String,
|
||||||
|
val handler: WebSocketHandler,
|
||||||
|
val autoWrap: Boolean = true,
|
||||||
|
val log: Boolean = false,
|
||||||
|
val compressed: Boolean = true,
|
||||||
|
val maxContextLength: Int = 4096,
|
||||||
|
private val headers: Map<String, String>? = null,
|
||||||
|
private val handshakerUri: URI? = null,
|
||||||
|
) {
|
||||||
|
private val uri: URI = URI.create(url)
|
||||||
internal var ch: Channel? = null
|
internal var ch: Channel? = null
|
||||||
|
|
||||||
fun open() {
|
fun open() {
|
||||||
@ -54,29 +65,39 @@ class WebSocketClient(uri: String, val handler: WebSocketHandler, val autoWrap:
|
|||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
val httpHeaders = DefaultHttpHeaders()
|
||||||
val handler = WebSocketClientChannelHandler(
|
headers?.forEach { (k, v) ->
|
||||||
WebSocketClientHandshakerFactory.newHandshaker(
|
httpHeaders[k] = v
|
||||||
uri, WebSocketVersion.V13, null, false, DefaultHttpHeaders()
|
}
|
||||||
), this, handler
|
val handshakerAdapter = WebSocketClientHandshakerAdapter(WebSocketClientHandshakerFactory.newHandshaker(
|
||||||
)
|
handshakerUri ?: uri, WebSocketVersion.V13, null, true, httpHeaders
|
||||||
|
), this, handler)
|
||||||
|
val handler = WebSocketClientChannelHandler(this, handler)
|
||||||
val bootstrap = Bootstrap()
|
val bootstrap = Bootstrap()
|
||||||
bootstrap.group(group)
|
bootstrap.group(group)
|
||||||
.channel(NioSocketChannel::class.java)
|
.channel(NioSocketChannel::class.java)
|
||||||
.handler(object : ChannelInitializer<SocketChannel>() {
|
.handler(object : ChannelInitializer<SocketChannel>() {
|
||||||
override fun initChannel(ch: SocketChannel) {
|
override fun initChannel(ch: SocketChannel) {
|
||||||
val pipeline = ch.pipeline()
|
ch.pipeline().apply {
|
||||||
if (sslCtx != null) {
|
if (log) {
|
||||||
pipeline.addLast(sslCtx.newHandler(ch.alloc(), host, port))
|
addLast(LoggingHandler())
|
||||||
}
|
}
|
||||||
pipeline.addLast(
|
if (sslCtx != null) {
|
||||||
HttpClientCodec(),
|
addLast(sslCtx.newHandler(ch.alloc(), host, port))
|
||||||
HttpObjectAggregator(4096),
|
}
|
||||||
WebSocketClientCompressionHandler.INSTANCE,
|
addLast(HttpClientCodec())
|
||||||
handler,
|
addLast(HttpObjectAggregator(maxContextLength))
|
||||||
)
|
if (compressed) {
|
||||||
|
addLast(WebSocketClientCompressionHandler.INSTANCE)
|
||||||
|
}
|
||||||
|
addLast(handshakerAdapter)
|
||||||
|
//if (log) {
|
||||||
|
// addLast(LoggingHandler())
|
||||||
|
//}
|
||||||
|
addLast(handler)
|
||||||
if (autoWrap) {
|
if (autoWrap) {
|
||||||
pipeline.addLast(WebSocketFrameWrapper)
|
addLast(WebSocketFrameWrapper)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -84,8 +105,12 @@ class WebSocketClient(uri: String, val handler: WebSocketHandler, val autoWrap:
|
|||||||
//handler.handshakeFuture().sync()
|
//handler.handshakeFuture().sync()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun close() {
|
fun close(reasonText: String? = null) {
|
||||||
|
if (reasonText == null) {
|
||||||
ch?.writeAndFlush(CloseWebSocketFrame())
|
ch?.writeAndFlush(CloseWebSocketFrame())
|
||||||
|
} else {
|
||||||
|
ch?.writeAndFlush(CloseWebSocketFrame(WebSocketCloseStatus.NORMAL_CLOSURE, reasonText))
|
||||||
|
}
|
||||||
ch?.closeFuture()?.sync()
|
ch?.closeFuture()?.sync()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,6 +152,44 @@ class WebSocketClient(uri: String, val handler: WebSocketHandler, val autoWrap:
|
|||||||
return ch!!.writeAndFlush(TextWebSocketFrame(data))
|
return ch!!.writeAndFlush(TextWebSocketFrame(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ping(data: ByteArray): ChannelFuture {
|
||||||
|
return ch!!.writeAndFlush(PingWebSocketFrame(Unpooled.wrappedBuffer(data)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ping(data: ByteBuffer): ChannelFuture {
|
||||||
|
return ch!!.writeAndFlush(
|
||||||
|
PingWebSocketFrame(
|
||||||
|
when (data) {
|
||||||
|
is NettyByteBuffer -> data.byteBuf
|
||||||
|
else -> Unpooled.wrappedBuffer(data.getBytes())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ping(data: ByteBuf): ChannelFuture {
|
||||||
|
return ch!!.writeAndFlush(PingWebSocketFrame(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pong(data: ByteArray): ChannelFuture {
|
||||||
|
return ch!!.writeAndFlush(PongWebSocketFrame(Unpooled.wrappedBuffer(data)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pong(data: ByteBuffer): ChannelFuture {
|
||||||
|
return ch!!.writeAndFlush(
|
||||||
|
PongWebSocketFrame(
|
||||||
|
when (data) {
|
||||||
|
is NettyByteBuffer -> data.byteBuf
|
||||||
|
else -> Unpooled.wrappedBuffer(data.getBytes())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pong(data: ByteBuf): ChannelFuture {
|
||||||
|
return ch!!.writeAndFlush(PongWebSocketFrame(data))
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val group: EventLoopGroup = NioEventLoopGroup()
|
private val group: EventLoopGroup = NioEventLoopGroup()
|
||||||
}
|
}
|
||||||
|
@ -5,32 +5,14 @@ import io.netty.channel.ChannelHandlerContext
|
|||||||
import io.netty.channel.ChannelPromise
|
import io.netty.channel.ChannelPromise
|
||||||
import io.netty.channel.SimpleChannelInboundHandler
|
import io.netty.channel.SimpleChannelInboundHandler
|
||||||
import io.netty.handler.codec.http.FullHttpResponse
|
import io.netty.handler.codec.http.FullHttpResponse
|
||||||
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame
|
import io.netty.handler.codec.http.websocketx.*
|
||||||
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame
|
|
||||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame
|
|
||||||
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker
|
|
||||||
import io.netty.util.CharsetUtil
|
import io.netty.util.CharsetUtil
|
||||||
|
|
||||||
|
|
||||||
class WebSocketClientChannelHandler(
|
class WebSocketClientChannelHandler(
|
||||||
private val handshaker: WebSocketClientHandshaker,
|
|
||||||
val client: WebSocketClient,
|
val client: WebSocketClient,
|
||||||
val handler: WebSocketHandler
|
val handler: WebSocketHandler
|
||||||
) : SimpleChannelInboundHandler<Any>() {
|
) : SimpleChannelInboundHandler<WebSocketFrame>() {
|
||||||
private var handshakeFuture: ChannelPromise? = null
|
|
||||||
|
|
||||||
fun handshakeFuture(): ChannelFuture? {
|
|
||||||
return handshakeFuture
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handlerAdded(ctx: ChannelHandlerContext) {
|
|
||||||
handshakeFuture = ctx.newPromise()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun channelActive(ctx: ChannelHandlerContext) {
|
|
||||||
client.ch = ctx.channel()
|
|
||||||
handshaker.handshake(ctx.channel())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun channelInactive(ctx: ChannelHandlerContext) {
|
override fun channelInactive(ctx: ChannelHandlerContext) {
|
||||||
handler.onClose(client)
|
handler.onClose(client)
|
||||||
@ -39,34 +21,12 @@ class WebSocketClientChannelHandler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun channelRead0(ctx: ChannelHandlerContext, msg: Any) {
|
override fun channelRead0(ctx: ChannelHandlerContext, msg: WebSocketFrame) {
|
||||||
val ch = ctx.channel()
|
val ch = ctx.channel()
|
||||||
if (!handshaker.isHandshakeComplete) {
|
|
||||||
// web socket client connected
|
|
||||||
handshaker.finishHandshake(ch, msg as FullHttpResponse)
|
|
||||||
handshakeFuture!!.setSuccess()
|
|
||||||
handler.onOpen(client)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (msg is FullHttpResponse) {
|
|
||||||
throw Exception("Unexpected FullHttpResponse (getStatus=${msg.status()}, content=${msg.content().toString(CharsetUtil.UTF_8)})")
|
|
||||||
}
|
|
||||||
when (msg) {
|
when (msg) {
|
||||||
is TextWebSocketFrame -> handler.readMessage(client, msg)
|
is TextWebSocketFrame -> handler.readMessage(client, msg)
|
||||||
is BinaryWebSocketFrame -> handler.readMessage(client, msg)
|
is BinaryWebSocketFrame -> handler.readMessage(client, msg)
|
||||||
is CloseWebSocketFrame -> ch.close()
|
is CloseWebSocketFrame -> ch.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
|
|
||||||
try {
|
|
||||||
handler.onError(client, cause)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
if (!handshakeFuture!!.isDone) {
|
|
||||||
handshakeFuture!!.setFailure(cause)
|
|
||||||
}
|
|
||||||
ctx.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
package cn.tursom.ws
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandlerContext
|
||||||
|
import io.netty.channel.ChannelPromise
|
||||||
|
import io.netty.channel.SimpleChannelInboundHandler
|
||||||
|
import io.netty.handler.codec.http.FullHttpResponse
|
||||||
|
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker
|
||||||
|
import io.netty.util.CharsetUtil
|
||||||
|
|
||||||
|
class WebSocketClientHandshakerAdapter(
|
||||||
|
private val handshaker: WebSocketClientHandshaker,
|
||||||
|
private val client: WebSocketClient,
|
||||||
|
private val handler: WebSocketHandler,
|
||||||
|
) : SimpleChannelInboundHandler<FullHttpResponse>() {
|
||||||
|
private var handshakeFuture: ChannelPromise? = null
|
||||||
|
|
||||||
|
override fun handlerAdded(ctx: ChannelHandlerContext) {
|
||||||
|
handshakeFuture = ctx.newPromise()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun channelActive(ctx: ChannelHandlerContext) {
|
||||||
|
client.ch = ctx.channel()
|
||||||
|
handshaker.handshake(ctx.channel())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun channelRead0(ctx: ChannelHandlerContext, msg: FullHttpResponse) {
|
||||||
|
if (!handshaker.isHandshakeComplete) {
|
||||||
|
handshaker.finishHandshake(ctx.channel(), msg)
|
||||||
|
handshakeFuture!!.setSuccess()
|
||||||
|
msg.retain()
|
||||||
|
ctx.fireChannelRead(msg)
|
||||||
|
handler.onOpen(client)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
throw Exception("Unexpected FullHttpResponse (getStatus=${msg.status()}, content=${
|
||||||
|
msg.content().toString(CharsetUtil.UTF_8)
|
||||||
|
})")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
|
||||||
|
try {
|
||||||
|
handler.onError(client, cause)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
if (!handshakeFuture!!.isDone) {
|
||||||
|
handshakeFuture!!.setFailure(cause)
|
||||||
|
}
|
||||||
|
ctx.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user