From 4b33cb69c35e46649b5c66ede103781a96d26a7a Mon Sep 17 00:00:00 2001 From: hengyunabc Date: Sun, 10 Nov 2019 02:48:08 +0800 Subject: [PATCH] support http and telnet in one port. #316 --- .../httptelnet/ProtocolDetectHandler.java | 6 +- .../httptelnet/TtyWebSocketFrameHandler.java | 111 ++++++++++++++++++ .../com/taobao/arthas/core/http/index.html | 3 +- 3 files changed, 116 insertions(+), 4 deletions(-) create mode 100644 core/src/main/java/com/taobao/arthas/core/shell/term/impl/httptelnet/TtyWebSocketFrameHandler.java diff --git a/core/src/main/java/com/taobao/arthas/core/shell/term/impl/httptelnet/ProtocolDetectHandler.java b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/httptelnet/ProtocolDetectHandler.java index 74d05a68c..4399eb2dc 100644 --- a/core/src/main/java/com/taobao/arthas/core/shell/term/impl/httptelnet/ProtocolDetectHandler.java +++ b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/httptelnet/ProtocolDetectHandler.java @@ -15,7 +15,6 @@ import io.netty.handler.stream.ChunkedWriteHandler; import io.netty.util.concurrent.ScheduledFuture; import io.termd.core.function.Consumer; import io.termd.core.function.Supplier; -import io.termd.core.http.netty.TtyWebSocketFrameHandler; import io.termd.core.telnet.TelnetHandler; import io.termd.core.telnet.netty.TelnetChannelHandler; import io.termd.core.tty.TtyConnection; @@ -52,7 +51,7 @@ public class ProtocolDetectHandler extends ChannelInboundHandlerAdapter { ctx.fireChannelActive(); // trigger TelnetChannelHandler init } - }, 500, TimeUnit.MILLISECONDS); + }, 1000, TimeUnit.MILLISECONDS); } @Override @@ -83,9 +82,10 @@ public class ProtocolDetectHandler extends ChannelInboundHandlerAdapter { pipeline.addLast(new HttpRequestHandler("/ws", new File("arthas-output"))); pipeline.addLast(new WebSocketServerProtocolHandler("/ws")); pipeline.addLast(new TtyWebSocketFrameHandler(channelGroup, ttyConnectionFactory)); + ctx.fireChannelActive(); } - ctx.fireChannelRead(in); pipeline.remove(this); + ctx.fireChannelRead(in); } } diff --git a/core/src/main/java/com/taobao/arthas/core/shell/term/impl/httptelnet/TtyWebSocketFrameHandler.java b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/httptelnet/TtyWebSocketFrameHandler.java new file mode 100644 index 000000000..b897525c9 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/httptelnet/TtyWebSocketFrameHandler.java @@ -0,0 +1,111 @@ +/* + * Copyright 2015 Julien Viet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.taobao.arthas.core.shell.term.impl.httptelnet; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.group.ChannelGroup; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; +import io.termd.core.function.Consumer; +import io.termd.core.http.HttpTtyConnection; +import io.termd.core.tty.TtyConnection; + +import java.util.concurrent.TimeUnit; + +/** + * @author Julien Viet + */ +public class TtyWebSocketFrameHandler extends SimpleChannelInboundHandler { + + private final ChannelGroup group; + private final Consumer handler; + private ChannelHandlerContext context; + private HttpTtyConnection conn; + + public TtyWebSocketFrameHandler(ChannelGroup group, Consumer handler) { + this.group = group; + this.handler = handler; + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + super.channelActive(ctx); + context = ctx; + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt == WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE) { + ctx.pipeline().remove(HttpRequestHandler.class); + group.add(ctx.channel()); + conn = new HttpTtyConnection() { + @Override + protected void write(byte[] buffer) { + ByteBuf byteBuf = Unpooled.buffer(); + byteBuf.writeBytes(buffer); + if (context != null) { + context.writeAndFlush(new TextWebSocketFrame(byteBuf)); + } + } + + @Override + public void schedule(Runnable task, long delay, TimeUnit unit) { + if (context != null) { + context.executor().schedule(task, delay, unit); + } + } + + @Override + public void execute(Runnable task) { + if (context != null) { + context.executor().execute(task); + } + } + + @Override + public void close() { + if (context != null) { + context.close(); + } + } + }; + handler.accept(conn); + } else { + super.userEventTriggered(ctx, evt); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + HttpTtyConnection tmp = conn; + context = null; + conn = null; + if (tmp != null) { + Consumer closeHandler = tmp.getCloseHandler(); + if (closeHandler != null) { + closeHandler.accept(null); + } + } + } + + public void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { + conn.writeToDecoder(msg.text()); + } +} diff --git a/core/src/main/resources/com/taobao/arthas/core/http/index.html b/core/src/main/resources/com/taobao/arthas/core/http/index.html index 72da26419..4b5fe0056 100644 --- a/core/src/main/resources/com/taobao/arthas/core/http/index.html +++ b/core/src/main/resources/com/taobao/arthas/core/http/index.html @@ -72,7 +72,7 @@
Port
- @@ -80,6 +80,7 @@
+ Arthas Output