mirror of
https://github.com/alibaba/arthas.git
synced 2024-04-21 10:21:39 +00:00
remove LocalTermServer
This commit is contained in:
+35
-4
@@ -12,13 +12,18 @@ import com.alibaba.arthas.channel.proto.RegisterResult;
|
||||
import io.grpc.ManagedChannel;
|
||||
import io.grpc.ManagedChannelBuilder;
|
||||
import io.grpc.stub.StreamObserver;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.util.concurrent.DefaultThreadFactory;
|
||||
import io.netty.util.concurrent.GlobalEventExecutor;
|
||||
import io.netty.util.concurrent.Promise;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@@ -40,15 +45,30 @@ public class ChannelClient {
|
||||
private ScheduledFuture<?> reconnectFuture;
|
||||
private String channelServerAddress;
|
||||
private int reconnectDelay = 5000;
|
||||
private EventLoopGroup group;
|
||||
|
||||
public ChannelClient(String host, int port) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.channelServerAddress = host + ":" + port;
|
||||
init();
|
||||
}
|
||||
|
||||
public ChannelClient(String channelServer) {
|
||||
setServerAddress(channelServer);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
group = new NioEventLoopGroup(1, new DefaultThreadFactory("arthas-ChannelWebsocketClient", true));
|
||||
executorService = Executors.newScheduledThreadPool(1, new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
final Thread t = new Thread(r, "arthas-channel-client");
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setServerAddress(String channelServer) {
|
||||
@@ -71,6 +91,7 @@ public class ChannelClient {
|
||||
}
|
||||
|
||||
public void start() {
|
||||
|
||||
isError = true;
|
||||
try {
|
||||
connect();
|
||||
@@ -98,6 +119,12 @@ public class ChannelClient {
|
||||
//ignore ex
|
||||
}
|
||||
}
|
||||
if (executorService != null) {
|
||||
executorService.shutdown();
|
||||
}
|
||||
if (group != null) {
|
||||
group.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
|
||||
private void connect() throws Exception {
|
||||
@@ -324,10 +351,6 @@ public class ChannelClient {
|
||||
this.requestListener = requestListener;
|
||||
}
|
||||
|
||||
public void setExecutorService(ScheduledExecutorService executorService) {
|
||||
this.executorService = executorService;
|
||||
}
|
||||
|
||||
public String getChannelServerAddress() {
|
||||
return channelServerAddress;
|
||||
}
|
||||
@@ -344,6 +367,14 @@ public class ChannelClient {
|
||||
this.reconnectDelay = reconnectDelay;
|
||||
}
|
||||
|
||||
public ScheduledExecutorService getExecutorService() {
|
||||
return executorService;
|
||||
}
|
||||
|
||||
public EventLoopGroup getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public interface RequestListener {
|
||||
void onRequest(ActionRequest request);
|
||||
}
|
||||
|
||||
-1
@@ -20,7 +20,6 @@ public class ChannelClientTest {
|
||||
final ChannelClient channelClient = new ChannelClient("localhost:7700");
|
||||
channelClient.setAgentInfoService(new TestAgentInfoServiceImpl());
|
||||
ScheduledExecutorService executorService = getExecutorService();
|
||||
channelClient.setExecutorService(executorService);
|
||||
channelClient.setRequestListener(new RequestHandler(channelClient, executorService));
|
||||
|
||||
channelClient.start();
|
||||
|
||||
@@ -28,7 +28,6 @@ import com.taobao.arthas.core.command.model.WelcomeModel;
|
||||
import com.taobao.arthas.core.distribution.PackingResultDistributor;
|
||||
import com.taobao.arthas.core.distribution.ResultDistributor;
|
||||
import com.taobao.arthas.core.distribution.impl.PackingResultDistributorImpl;
|
||||
import com.taobao.arthas.core.server.ArthasBootstrap;
|
||||
import com.taobao.arthas.core.shell.cli.CliToken;
|
||||
import com.taobao.arthas.core.shell.cli.CliTokens;
|
||||
import com.taobao.arthas.core.shell.cli.Completion;
|
||||
@@ -42,13 +41,13 @@ import com.taobao.arthas.core.shell.system.JobListener;
|
||||
import com.taobao.arthas.core.shell.system.impl.InternalCommandManager;
|
||||
import com.taobao.arthas.core.shell.term.SignalHandler;
|
||||
import com.taobao.arthas.core.shell.term.Term;
|
||||
import com.taobao.arthas.core.shell.term.impl.LocalTermServer;
|
||||
import com.taobao.arthas.core.shell.term.impl.http.api.ApiState;
|
||||
import com.taobao.arthas.core.util.ArthasBanner;
|
||||
import com.taobao.arthas.core.util.DateUtils;
|
||||
import com.taobao.arthas.core.util.StringUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||
import io.netty.util.concurrent.Future;
|
||||
import io.netty.util.concurrent.GenericFutureListener;
|
||||
@@ -76,6 +75,7 @@ public class ChannelRequestHandler implements ChannelClient.RequestListener {
|
||||
public static final int DEFAULT_EXEC_TIMEOUT = 30000;
|
||||
private final ScheduledExecutorService executorService;
|
||||
|
||||
private EventLoopGroup group;
|
||||
private ChannelClient channelClient;
|
||||
private final SessionManager sessionManager;
|
||||
private final HistoryManager historyManager;
|
||||
@@ -92,14 +92,8 @@ public class ChannelRequestHandler implements ChannelClient.RequestListener {
|
||||
commandManager = this.sessionManager.getCommandManager();
|
||||
jobController = this.sessionManager.getJobController();
|
||||
|
||||
executorService = Executors.newScheduledThreadPool(1, new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
final Thread t = new Thread(r, "arthas-command-execute");
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
}
|
||||
});
|
||||
group = channelClient.getGroup();
|
||||
executorService = channelClient.getExecutorService();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -189,8 +183,8 @@ public class ChannelRequestHandler implements ChannelClient.RequestListener {
|
||||
|
||||
final BlockingQueue<ConsoleData> queue = new LinkedBlockingQueue<ConsoleData>(1000);
|
||||
|
||||
LocalTermServer localTermServer = ArthasBootstrap.getInstance().getLocalTermServer();
|
||||
Channel clientChannel = localTermServer.connect(new Consumer<TextWebSocketFrame>() {
|
||||
LocalWebsocketClient websocketClient = new LocalWebsocketClient();
|
||||
Channel clientChannel = websocketClient.connectLocalServer(group, new Consumer<TextWebSocketFrame>() {
|
||||
@Override
|
||||
public void accept(TextWebSocketFrame frame) {
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.taobao.arthas.core.channel;
|
||||
|
||||
import com.alibaba.arthas.deps.org.slf4j.Logger;
|
||||
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
|
||||
import com.alibaba.arthas.tunnel.client.LocalFrameHandler;
|
||||
import com.taobao.arthas.common.ArthasConstants;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.channel.local.LocalAddress;
|
||||
import io.netty.channel.local.LocalChannel;
|
||||
import io.netty.handler.codec.http.DefaultHttpHeaders;
|
||||
import io.netty.handler.codec.http.HttpClientCodec;
|
||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandler;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
|
||||
import io.netty.util.concurrent.GenericFutureListener;
|
||||
import io.termd.core.function.Consumer;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
|
||||
public class LocalWebsocketClient {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(LocalWebsocketClient.class);
|
||||
|
||||
public Channel connectLocalServer(EventLoopGroup group, final Consumer<TextWebSocketFrame> clientHandler) throws Exception {
|
||||
try {
|
||||
logger.info("connecting to local arthas server ..");
|
||||
// 入参URI实际无意义,只为了程序不出错
|
||||
WebSocketClientHandshaker newHandshaker = WebSocketClientHandshakerFactory.newHandshaker(new URI("ws://127.0.0.1:8563/ws"),
|
||||
WebSocketVersion.V13, null, true, new DefaultHttpHeaders());
|
||||
final WebSocketClientProtocolHandler websocketClientHandler = new WebSocketClientProtocolHandler(
|
||||
newHandshaker);
|
||||
final LocalFrameHandler localFrameHandler = new LocalFrameHandler();
|
||||
|
||||
Bootstrap b = new Bootstrap();
|
||||
b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000);
|
||||
b.group(group).channel(LocalChannel.class)
|
||||
.handler(new ChannelInitializer<LocalChannel>() {
|
||||
@Override
|
||||
protected void initChannel(LocalChannel ch) {
|
||||
ChannelPipeline p = ch.pipeline();
|
||||
p.addLast(new HttpClientCodec(), new HttpObjectAggregator(8192), websocketClientHandler,
|
||||
localFrameHandler);
|
||||
}
|
||||
});
|
||||
|
||||
LocalAddress localAddress = new LocalAddress(ArthasConstants.NETTY_LOCAL_ADDRESS);
|
||||
Channel localChannel = b.connect(localAddress).sync().channel();
|
||||
// Channel localChannel = b.connect(localServerURI.getHost(), localServerURI.getPort()).sync().channel();
|
||||
ChannelPromise handshakeFuture = localFrameHandler.handshakeFuture();
|
||||
handshakeFuture.addListener(new GenericFutureListener<ChannelFuture>() {
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture future) throws Exception {
|
||||
ChannelPipeline pipeline = future.channel().pipeline();
|
||||
pipeline.remove(localFrameHandler);
|
||||
pipeline.addLast(new LocalClientHandler(clientHandler));
|
||||
}
|
||||
});
|
||||
|
||||
handshakeFuture.sync();
|
||||
logger.info("connect to local arthas server success");
|
||||
|
||||
return localChannel;
|
||||
} catch (Exception e){
|
||||
logger.error("connect to local arthas server error", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static class LocalClientHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
|
||||
Consumer<TextWebSocketFrame> clientHandler;
|
||||
|
||||
public LocalClientHandler(Consumer<TextWebSocketFrame> clientHandler) {
|
||||
this.clientHandler = clientHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
|
||||
clientHandler.accept(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
logger.error("Local websocket client handle error", cause);
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.security.CodeSource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -52,7 +51,6 @@ import com.taobao.arthas.core.shell.impl.ShellServerImpl;
|
||||
import com.taobao.arthas.core.shell.session.SessionManager;
|
||||
import com.taobao.arthas.core.shell.session.impl.SessionManagerImpl;
|
||||
import com.taobao.arthas.core.shell.term.impl.HttpTermServer;
|
||||
import com.taobao.arthas.core.shell.term.impl.LocalTermServer;
|
||||
import com.taobao.arthas.core.shell.term.impl.http.api.HttpApiHandler;
|
||||
import com.taobao.arthas.core.shell.term.impl.httptelnet.HttpTelnetTermServer;
|
||||
import com.taobao.arthas.core.util.ArthasBanner;
|
||||
@@ -354,7 +352,7 @@ public class ArthasBootstrap {
|
||||
options.getConnectionTimeout(), workerGroup));
|
||||
} else {
|
||||
// listen local address in VM communication
|
||||
if (configure.getTunnelServer() != null) {
|
||||
if (configure.getTunnelServer() != null || configure.getChannelServer() != null) {
|
||||
shellServer.registerTermServer(new HttpTermServer(configure.getIp(), configure.getHttpPort(),
|
||||
options.getConnectionTimeout(), workerGroup));
|
||||
}
|
||||
@@ -376,7 +374,6 @@ public class ArthasBootstrap {
|
||||
try {
|
||||
channelClient = new ChannelClient(configure.getChannelServer());
|
||||
channelClient.setAgentInfoService(new AgentInfoServiceImpl(configure));
|
||||
channelClient.setExecutorService(executorService);
|
||||
channelClient.setRequestListener(new ChannelRequestHandler(channelClient, sessionManager, historyManager));
|
||||
channelClient.start();
|
||||
} catch (Throwable e) {
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
package com.taobao.arthas.core.shell.term.impl;
|
||||
|
||||
import com.alibaba.arthas.deps.org.slf4j.Logger;
|
||||
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
|
||||
import com.taobao.arthas.core.shell.future.Future;
|
||||
import com.taobao.arthas.core.shell.handlers.Handler;
|
||||
import com.taobao.arthas.core.shell.term.Term;
|
||||
import com.taobao.arthas.core.shell.term.TermServer;
|
||||
import com.taobao.arthas.core.shell.term.impl.local.LocalTtyServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||
import io.netty.util.concurrent.EventExecutorGroup;
|
||||
import io.termd.core.function.Consumer;
|
||||
import io.termd.core.tty.TtyConnection;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author gongdewei 2020/9/1
|
||||
*/
|
||||
public class LocalTermServer extends TermServer {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(LocalTermServer.class);
|
||||
|
||||
private Handler<Term> termHandler;
|
||||
private LocalTtyServerBootstrap bootstrap;
|
||||
private String localAddr;
|
||||
private long connectionTimeout;
|
||||
private EventExecutorGroup workerGroup;
|
||||
|
||||
public LocalTermServer(String localAddr, long connectionTimeout, EventExecutorGroup workerGroup) {
|
||||
this.localAddr = localAddr;
|
||||
this.connectionTimeout = connectionTimeout;
|
||||
this.workerGroup = workerGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TermServer termHandler(Handler<Term> handler) {
|
||||
this.termHandler = handler;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TermServer listen(Handler<Future<TermServer>> listenHandler) {
|
||||
// TODO: charset and inputrc from options
|
||||
bootstrap = new LocalTtyServerBootstrap(workerGroup).setAddr(localAddr);
|
||||
try {
|
||||
bootstrap.start(new Consumer<TtyConnection>() {
|
||||
@Override
|
||||
public void accept(final TtyConnection conn) {
|
||||
termHandler.handle(new TermImpl(Helper.loadKeymap(), conn));
|
||||
}
|
||||
}).get(connectionTimeout, TimeUnit.MILLISECONDS);
|
||||
listenHandler.handle(Future.<TermServer>succeededFuture());
|
||||
logger.info("local term server is started.");
|
||||
} catch (Throwable t) {
|
||||
logger.error("start local term server error" , t);
|
||||
listenHandler.handle(Future.<TermServer>failedFuture(t));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int actualPort() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
close(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(Handler<Future<Void>> completionHandler) {
|
||||
if (bootstrap != null) {
|
||||
bootstrap.stop();
|
||||
if (completionHandler != null) {
|
||||
completionHandler.handle(Future.<Void>succeededFuture());
|
||||
}
|
||||
} else {
|
||||
if (completionHandler != null) {
|
||||
completionHandler.handle(Future.<Void>failedFuture("telnet term server not started"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Channel connect(Consumer<TextWebSocketFrame> clientHandler) throws InterruptedException {
|
||||
return bootstrap.connect(clientHandler);
|
||||
}
|
||||
}
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
package com.taobao.arthas.core.shell.term.impl.local;
|
||||
|
||||
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.termd.core.function.Consumer;
|
||||
import io.termd.core.http.HttpTtyConnection;
|
||||
import io.termd.core.tty.TtyConnection;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author gongdewei 2020/9/1
|
||||
*/
|
||||
public class LocalTtyChannelHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
|
||||
|
||||
|
||||
private final ChannelGroup group;
|
||||
private final Consumer<TtyConnection> handler;
|
||||
private HttpTtyConnection conn;
|
||||
private ChannelHandlerContext context;
|
||||
|
||||
public LocalTtyChannelHandler(ChannelGroup group, Consumer<TtyConnection> handler) {
|
||||
this.group = group;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
super.channelActive(ctx);
|
||||
context = ctx;
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
HttpTtyConnection tmp = conn;
|
||||
context = null;
|
||||
conn = null;
|
||||
if (tmp != null) {
|
||||
Consumer<Void> closeHandler = tmp.getCloseHandler();
|
||||
if (closeHandler != null) {
|
||||
closeHandler.accept(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
|
||||
conn.writeToDecoder(msg.text());
|
||||
}
|
||||
}
|
||||
-153
@@ -1,153 +0,0 @@
|
||||
package com.taobao.arthas.core.shell.term.impl.local;
|
||||
|
||||
import com.alibaba.arthas.deps.org.slf4j.Logger;
|
||||
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.channel.group.ChannelGroup;
|
||||
import io.netty.channel.group.DefaultChannelGroup;
|
||||
import io.netty.channel.local.LocalAddress;
|
||||
import io.netty.channel.local.LocalChannel;
|
||||
import io.netty.channel.local.LocalServerChannel;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||
import io.netty.handler.logging.LogLevel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
import io.netty.util.concurrent.DefaultThreadFactory;
|
||||
import io.netty.util.concurrent.EventExecutorGroup;
|
||||
import io.netty.util.concurrent.Future;
|
||||
import io.netty.util.concurrent.GenericFutureListener;
|
||||
import io.netty.util.concurrent.ImmediateEventExecutor;
|
||||
import io.termd.core.function.Consumer;
|
||||
import io.termd.core.tty.TtyConnection;
|
||||
import io.termd.core.util.CompletableFuture;
|
||||
import io.termd.core.util.Helper;
|
||||
|
||||
/**
|
||||
* Convenience class for quickly starting a Netty Tty server.
|
||||
*
|
||||
*/
|
||||
public class LocalTtyServerBootstrap {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(LocalTtyServerBootstrap.class);
|
||||
|
||||
private final ChannelGroup channelGroup = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE);
|
||||
private String addr;
|
||||
private EventLoopGroup serverGroup;
|
||||
private Channel serverChannel;
|
||||
private EventExecutorGroup workerGroup;
|
||||
|
||||
public LocalTtyServerBootstrap(EventExecutorGroup workerGroup) {
|
||||
this.workerGroup = workerGroup;
|
||||
this.addr = "local-tty-server";
|
||||
}
|
||||
|
||||
public String getAddr() {
|
||||
return addr;
|
||||
}
|
||||
|
||||
public LocalTtyServerBootstrap setAddr(String addr) {
|
||||
this.addr = addr;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void start(Consumer<TtyConnection> handler, final Consumer<Throwable> doneHandler) {
|
||||
serverGroup = new NioEventLoopGroup(new DefaultThreadFactory("arthas-LocalWebsocketTtyBootstrap", true));
|
||||
|
||||
ServerBootstrap b = new ServerBootstrap();
|
||||
b.group(serverGroup).channel(LocalServerChannel.class).handler(new LoggingHandler(LogLevel.TRACE))
|
||||
.childHandler(new LocalTtyServerInitializer(channelGroup, handler, workerGroup));
|
||||
|
||||
// Address to bind on / connect to.
|
||||
final LocalAddress localAddr = new LocalAddress(addr);
|
||||
|
||||
final ChannelFuture f = b.bind(localAddr);
|
||||
f.addListener(new GenericFutureListener<Future<? super Void>>() {
|
||||
@Override
|
||||
public void operationComplete(Future<? super Void> future) throws Exception {
|
||||
if (future.isSuccess()) {
|
||||
serverChannel = f.channel();
|
||||
doneHandler.accept(null);
|
||||
} else {
|
||||
doneHandler.accept(future.cause());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public Channel connect(final Consumer<TextWebSocketFrame> clientHandler) throws InterruptedException {
|
||||
final LocalAddress localAddr = new LocalAddress(addr);
|
||||
//start client
|
||||
Bootstrap cb = new Bootstrap();
|
||||
cb.group(serverGroup)
|
||||
.channel(LocalChannel.class)
|
||||
.handler(new ChannelInitializer<LocalChannel>() {
|
||||
@Override
|
||||
public void initChannel(LocalChannel ch) throws Exception {
|
||||
ch.pipeline().addLast(
|
||||
new LoggingHandler(LogLevel.TRACE),
|
||||
new LocalClientHandler(clientHandler));
|
||||
}
|
||||
});
|
||||
|
||||
// Start the client.
|
||||
return cb.connect(localAddr).sync().channel();
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> start(Consumer<TtyConnection> handler) {
|
||||
CompletableFuture<Void> fut = new CompletableFuture<Void>();
|
||||
start(handler, Helper.startedHandler(fut));
|
||||
return fut;
|
||||
}
|
||||
|
||||
public void stop(final Consumer<Throwable> doneHandler) {
|
||||
if (serverChannel != null) {
|
||||
serverChannel.close();
|
||||
}
|
||||
|
||||
channelGroup.close().addListener(new GenericFutureListener<Future<? super Void>>() {
|
||||
@Override
|
||||
public void operationComplete(Future<? super Void> future) throws Exception {
|
||||
try {
|
||||
doneHandler.accept(future.cause());
|
||||
} finally {
|
||||
serverGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> stop() {
|
||||
CompletableFuture<Void> fut = new CompletableFuture<Void>();
|
||||
stop(Helper.stoppedHandler(fut));
|
||||
return fut;
|
||||
}
|
||||
|
||||
private static class LocalClientHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
|
||||
Consumer<TextWebSocketFrame> clientHandler;
|
||||
|
||||
public LocalClientHandler(Consumer<TextWebSocketFrame> clientHandler) {
|
||||
this.clientHandler = clientHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
|
||||
clientHandler.accept(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
logger.error("Local tty client handle error", cause);
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
package com.taobao.arthas.core.shell.term.impl.local;
|
||||
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.group.ChannelGroup;
|
||||
import io.netty.channel.local.LocalChannel;
|
||||
import io.netty.util.concurrent.EventExecutorGroup;
|
||||
import io.termd.core.function.Consumer;
|
||||
import io.termd.core.tty.TtyConnection;
|
||||
|
||||
|
||||
public class LocalTtyServerInitializer extends ChannelInitializer<LocalChannel> {
|
||||
|
||||
private final ChannelGroup group;
|
||||
private final Consumer<TtyConnection> handler;
|
||||
private EventExecutorGroup workerGroup;
|
||||
|
||||
public LocalTtyServerInitializer(ChannelGroup group, Consumer<TtyConnection> handler, EventExecutorGroup workerGroup) {
|
||||
this.group = group;
|
||||
this.handler = handler;
|
||||
this.workerGroup = workerGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initChannel(LocalChannel ch) throws Exception {
|
||||
|
||||
ChannelPipeline pipeline = ch.pipeline();
|
||||
// pipeline.addLast(new HttpServerCodec());
|
||||
// pipeline.addLast(new ChunkedWriteHandler());
|
||||
// pipeline.addLast(new HttpObjectAggregator(64 * 1024));
|
||||
// pipeline.addLast(workerGroup, "HttpRequestHandler", new HttpRequestHandler("/ws", new File("arthas-output")));
|
||||
// pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
|
||||
// pipeline.addLast(new TtyWebSocketFrameHandler(group, handler));
|
||||
|
||||
pipeline.addLast(new LocalTtyChannelHandler(group, handler));
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user