前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >聊聊arthas的HttpTermServer

聊聊arthas的HttpTermServer

原创
作者头像
code4it
发布2024-02-21 09:38:57
1070
发布2024-02-21 09:38:57
举报
文章被收录于专栏:码匠的流水账码匠的流水账

本文主要研究一下arthas的HttpTermServer

TermServer

com/taobao/arthas/core/shell/term/TermServer.java

代码语言:javascript
复制
public abstract class TermServer {

    /**
     * Create a term server for the Telnet protocol.
     *
     * @param configure
     * @return the term server
     */
    public static TermServer createTelnetTermServer(Configure configure, ShellServerOptions options) {
        int port = configure.getTelnetPort() != null ? configure.getTelnetPort() : ArthasConstants.TELNET_PORT;
        return new TelnetTermServer(configure.getIp(), port, options.getConnectionTimeout());
    }

    /**
     * Create a term server for the HTTP protocol, using an existing router.
     *
     * @return the term server
     */
    public static TermServer createHttpTermServer() {
        // TODO
        return null;
    }

    /**
     * Set the term handler that will receive incoming client connections. When a remote terminal connects
     * the {@code handler} will be called with the {@link Term} which can be used to interact with the remote
     * terminal.
     *
     * @param handler the term handler
     * @return this object
     */
    public abstract TermServer termHandler(Handler<Term> handler);

    /**
     * Bind the term server, the {@link #termHandler(Handler)} must be set before.
     *
     * @return this object
     */
    public TermServer listen() {
        return listen(null);
    }

    /**
     * Bind the term server, the {@link #termHandler(Handler)} must be set before.
     *
     * @param listenHandler the listen handler
     * @return this object
     */
    public abstract TermServer listen(Handler<Future<TermServer>> listenHandler);

    /**
     * The actual port the server is listening on. This is useful if you bound the server specifying 0 as port number
     * signifying an ephemeral port
     *
     * @return the actual port the server is listening on.
     */
    public abstract int actualPort();

    /**
     * Close the server. This will close any currently open connections. The close may not complete until after this
     * method has returned.
     */
    public abstract void close();

    /**
     * Like {@link #close} but supplying a handler that will be notified when close is complete.
     *
     * @param completionHandler the handler to be notified when the term server is closed
     */
    public abstract void close(Handler<Future<Void>> completionHandler);

}

TermServer是一个抽象类,它定义了termHandler、listen、actualPort、close抽象方法

HttpTermServer

com/taobao/arthas/core/shell/term/impl/HttpTermServer.java

代码语言:javascript
复制
public class HttpTermServer extends TermServer {

    private static final Logger logger = LoggerFactory.getLogger(HttpTermServer.class);

    private Handler<Term> termHandler;
    private NettyWebsocketTtyBootstrap bootstrap;
    private String hostIp;
    private int port;
    private long connectionTimeout;
    private EventExecutorGroup workerGroup;
    private HttpSessionManager httpSessionManager;

    public HttpTermServer(String hostIp, int port, long connectionTimeout, EventExecutorGroup workerGroup, HttpSessionManager httpSessionManager) {
        this.hostIp = hostIp;
        this.port = port;
        this.connectionTimeout = connectionTimeout;
        this.workerGroup = workerGroup;
        this.httpSessionManager = httpSessionManager;
    }

    @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 NettyWebsocketTtyBootstrap(workerGroup, httpSessionManager).setHost(hostIp).setPort(port);
        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());
        } catch (Throwable t) {
            logger.error("Error listening to port " + port, t);
            listenHandler.handle(Future.<TermServer>failedFuture(t));
        }
        return this;
    }

    @Override
    public int actualPort() {
        return bootstrap.getPort();
    }

    @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"));
            }
        }
    }
}

HttpTermServer继承了TermServer,其listen方法创建NettyWebsocketTtyBootstrap,然后执行其start方法,其accept方法执行的是termHandler.handle(new TermImpl(Helper.loadKeymap(), conn)),最后执行listenHandler.handle(Future.succeededFuture());其close方法执行的是bootstrap.stop()

Handler

com/taobao/arthas/core/shell/handlers/Handler.java

代码语言:javascript
复制
public interface Handler<E> {
    /**
     * Something has happened, so handle it.
     *
     * @param event the event to handle
     */
    void handle(E event);
}

Handler定义了handle方法

TermServerTermHandler

com/taobao/arthas/core/shell/handlers/server/TermServerTermHandler.java

代码语言:javascript
复制
public class TermServerTermHandler implements Handler<Term> {
    private ShellServerImpl shellServer;

    public TermServerTermHandler(ShellServerImpl shellServer) {
        this.shellServer = shellServer;
    }

    @Override
    public void handle(Term term) {
        shellServer.handleTerm(term);
    }
}

TermServerTermHandler实现了Handler接口,其handle方法执行的是shellServer.handleTerm(term)

ShellServerImpl

com/taobao/arthas/core/shell/impl/ShellServerImpl.java

代码语言:javascript
复制
    public void handleTerm(Term term) {
        synchronized (this) {
            // That might happen with multiple ser
            if (closed) {
                term.close();
                return;
            }
        }

        ShellImpl session = createShell(term);
        tryUpdateWelcomeMessage();
        session.setWelcome(welcomeMessage);
        session.closedFuture.setHandler(new SessionClosedHandler(this, session));
        session.init();
        sessions.put(session.id, session); // Put after init so the close handler on the connection is set
        session.readline(); // Now readline
    }

ShellServerImpl的handleTerm方法创建ShellImpl,然后执行init,最后执行readline

readline

com/taobao/arthas/core/shell/impl/ShellImpl.java

代码语言:javascript
复制
    public void readline() {
        term.readline(prompt, new ShellLineHandler(this),
                new CommandManagerCompletionHandler(commandManager));
    }

ShellImpl的readline委托给了Term,传入ShellLineHandler

ShellLineHandler

com/taobao/arthas/core/shell/handlers/shell/ShellLineHandler.java

代码语言:javascript
复制
    public void handle(String line) {
        if (line == null) {
            // EOF
            handleExit();
            return;
        }

        List<CliToken> tokens = CliTokens.tokenize(line);
        CliToken first = TokenUtils.findFirstTextToken(tokens);
        if (first == null) {
            // For now do like this
            shell.readline();
            return;
        }

        String name = first.value();
        if (name.equals("exit") || name.equals("logout") || name.equals("q") || name.equals("quit")) {
            handleExit();
            return;
        } else if (name.equals("jobs")) {
            handleJobs();
            return;
        } else if (name.equals("fg")) {
            handleForeground(tokens);
            return;
        } else if (name.equals("bg")) {
            handleBackground(tokens);
            return;
        } else if (name.equals("kill")) {
            handleKill(tokens);
            return;
        }

        Job job = createJob(tokens);
        if (job != null) {
            job.run();
        }
    }

ShellLineHandler的handle方法才是真正处理命令的地方,它支持了exit、logout、q、quit、jobs、fg、bg、kill命令

小结

HttpTermServer继承了TermServer,其listen方法创建NettyWebsocketTtyBootstrap,然后执行其start方法,其accept方法执行的是termHandler.handle(new TermImpl(Helper.loadKeymap(), conn)),最后执行listenHandler.handle(Future.succeededFuture());其close方法执行的是bootstrap.stop()。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • TermServer
  • HttpTermServer
  • Handler
  • TermServerTermHandler
  • ShellServerImpl
  • readline
  • ShellLineHandler
  • 小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档