From 65d71e79103282494945ce10d228d2df303dd62c Mon Sep 17 00:00:00 2001 From: Hevake Date: Sun, 6 Mar 2022 19:02:58 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86terminal?= =?UTF-8?q?=EF=BC=9A=201.=E5=9C=A8TerminalInteract=E4=B8=AD=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E4=BA=86options=E5=8F=82=E6=95=B0=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=EF=BC=8C=E4=BD=BF=E4=B9=8B=E6=94=AF=E6=8C=81=E5=BC=80=E5=85=B3?= =?UTF-8?q?Echo,PrintWelcome,PrintPromt=E5=8A=9F=E8=83=BD;=202.=E4=BF=AE?= =?UTF-8?q?=E6=94=B9KeyEventScanner,=E4=BD=BF=E4=B9=8B=E6=94=AF=E6=8C=810x?= =?UTF-8?q?0A=E7=9A=84=E5=91=BD=E4=BB=A4=E7=BB=93=E6=9D=9F=E7=AC=A6;=203.?= =?UTF-8?q?=E6=94=AF=E6=8C=81nc=E7=9B=B4=E6=8E=A5=E8=BF=9E=E6=8E=A5?= =?UTF-8?q?=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- terminal/example/basic/Makefile | 2 +- terminal/example/basic/main.cpp | 4 +- terminal/impl/key_event_scanner.cpp | 3 ++ terminal/impl/key_event_scanner.h | 1 + terminal/impl/key_event_scanner_test.cpp | 7 ++++ terminal/impl/session_context.h | 2 + terminal/impl/telnetd.cpp | 8 ++++ terminal/impl/terminal.cpp | 50 ++++++++++++++++++------ terminal/impl/terminal.h | 3 ++ terminal/impl/terminal_key_events.cpp | 41 +++++++++++-------- terminal/terminal.cpp | 10 +++++ terminal/terminal.h | 3 ++ terminal/terminal_interact.h | 8 ++++ 13 files changed, 110 insertions(+), 32 deletions(-) diff --git a/terminal/example/basic/Makefile b/terminal/example/basic/Makefile index 3cdd016..bb4d9fa 100644 --- a/terminal/example/basic/Makefile +++ b/terminal/example/basic/Makefile @@ -3,7 +3,7 @@ include ../build_env.mk TARGET := demo OBJECTS := main.o CXXFLAGS += -ggdb -DLOG_MODULE_ID='"demo"' -LDFLAGS += -L.. -ltbox_terminal -ltbox_util -ltbox_network -ltbox_event -ltbox_base -levent_core -lev -lpthread +LDFLAGS += -L.. -ltbox_terminal -ltbox_util -ltbox_network -ltbox_event -ltbox_base -lpthread CXXFLAGS += -fsanitize=address -fno-omit-frame-pointer LDFLAGS += -fsanitize=address -static-libasan diff --git a/terminal/example/basic/main.cpp b/terminal/example/basic/main.cpp index c16ac4e..960410f 100644 --- a/terminal/example/basic/main.cpp +++ b/terminal/example/basic/main.cpp @@ -44,10 +44,10 @@ int main(int argc, char **argv) //! 注册ctrl+C停止信号 auto *sp_stop_ev = sp_loop->newSignalEvent(); SetScopeExitAction([sp_stop_ev] { delete sp_stop_ev; }); - sp_stop_ev->initialize(SIGINT, Event::Mode::kOneshot); + sp_stop_ev->initialize(std::set{SIGINT,SIGTERM}, Event::Mode::kOneshot); //! 指定ctrl+C时要做的事务 sp_stop_ev->setCallback( - [&] { + [&] (int) { telnetd.stop(); sp_loop->exitLoop(); //! (3) 退出事件循环 } diff --git a/terminal/impl/key_event_scanner.cpp b/terminal/impl/key_event_scanner.cpp index 731cd09..8ecf832 100644 --- a/terminal/impl/key_event_scanner.cpp +++ b/terminal/impl/key_event_scanner.cpp @@ -23,6 +23,9 @@ KeyEventScanner::Status KeyEventScanner::next(uint8_t byte) } else if (byte == 0x0d) { step_ = Step::k0d; return Status::kUnsure; + } else if (byte == 0x0a) { + result_ = Result::kEnter; + return Status::kEnsure; } else if (byte == 0x1b) { step_ = Step::k1b; return Status::kUnsure; diff --git a/terminal/impl/key_event_scanner.h b/terminal/impl/key_event_scanner.h index 505b5a5..79c6f04 100644 --- a/terminal/impl/key_event_scanner.h +++ b/terminal/impl/key_event_scanner.h @@ -15,6 +15,7 @@ namespace tbox::terminal { * - Backspace: 7f|08 * - ESC: 1b * - Enter: 0d [00|0a] + * 0a * * - Alt+?: 1b ? * - Ctrl+Alt+?: c2 ?+0x20 diff --git a/terminal/impl/key_event_scanner_test.cpp b/terminal/impl/key_event_scanner_test.cpp index 9f686b4..ca81431 100644 --- a/terminal/impl/key_event_scanner_test.cpp +++ b/terminal/impl/key_event_scanner_test.cpp @@ -93,6 +93,13 @@ TEST(KeyEventScanner, Enter_3) EXPECT_EQ(ks.result(), KeyEventScanner::Result::kEnter); } +TEST(KeyEventScanner, Enter_4) +{ + KeyEventScanner ks; + EXPECT_EQ(ks.next(0x0a), KeyEventScanner::Status::kEnsure); + EXPECT_EQ(ks.result(), KeyEventScanner::Result::kEnter); +} + TEST(KeyEventScanner, Alt) { KeyEventScanner ks; diff --git a/terminal/impl/session_context.h b/terminal/impl/session_context.h index 9c6744f..83b9d14 100644 --- a/terminal/impl/session_context.h +++ b/terminal/impl/session_context.h @@ -12,6 +12,8 @@ struct SessionContext { Connection *wp_conn = nullptr; SessionToken token; + uint32_t options = 0; + std::string curr_input; size_t cursor = 0; diff --git a/terminal/impl/telnetd.cpp b/terminal/impl/telnetd.cpp index f0632f4..75f4fa4 100644 --- a/terminal/impl/telnetd.cpp +++ b/terminal/impl/telnetd.cpp @@ -113,6 +113,7 @@ void Telnetd::Impl::onTcpConnected(const TcpServer::ClientToken &ct) sendNego(ct, kWILL, kECHO); sendNego(ct, kWILL, kSGA); + wp_terminal_->setOptions(st, TerminalInteract::kPrintWelcome | TerminalInteract::kPrintPrompt); wp_terminal_->onBegin(st); } @@ -225,9 +226,16 @@ void Telnetd::Impl::onRecvString(const TcpServer::ClientToken &ct, const std::st void Telnetd::Impl::onRecvNego(const TcpServer::ClientToken &ct, Cmd cmd, Opt opt) { LogTrace("cmd:%x, opt:%x", cmd, opt); + auto st = client_to_session_.at(ct); if (cmd == Cmd::kDONT) sendNego(ct, Cmd::kWONT, opt); + else if (cmd == Cmd::kDO) { + if (opt == Opt::kECHO) { + auto opts = wp_terminal_->getOptions(st); + wp_terminal_->setOptions(st, opts | TerminalInteract::kEnableEcho); + } + } } void Telnetd::Impl::onRecvCmd(const TcpServer::ClientToken &ct, Cmd cmd) diff --git a/terminal/impl/terminal.cpp b/terminal/impl/terminal.cpp index e7aabe4..308baa8 100644 --- a/terminal/impl/terminal.cpp +++ b/terminal/impl/terminal.cpp @@ -54,18 +54,38 @@ bool Terminal::Impl::deleteSession(const SessionToken &st) return false; } +uint32_t Terminal::Impl::getOptions(const SessionToken &st) const +{ + auto s = sessions_.at(st); + if (s == nullptr) + return 0; + + return s->options; +} + +void Terminal::Impl::setOptions(const SessionToken &st, uint32_t options) +{ + auto s = sessions_.at(st); + if (s == nullptr) + return; + + s->options = options; +} + bool Terminal::Impl::onBegin(const SessionToken &st) { auto s = sessions_.at(st); if (s == nullptr) return false; - s->wp_conn->send(st, - "\r\n" - "Welcome to CppTBox Terminal.\r\n" - "Type 'help' for more information.\r\n" - "\r\n" - ); + if (s->options & kPrintWelcome) { + s->wp_conn->send(st, + "\r\n" + "Welcome to CppTBox Terminal.\r\n" + "Type 'help' for more information.\r\n" + "\r\n" + ); + } printPrompt(s); return true; @@ -161,7 +181,8 @@ bool Terminal::Impl::onRecvWindowSize(const SessionToken &st, uint16_t w, uint16 void Terminal::Impl::printPrompt(SessionContext *s) { - s->wp_conn->send(s->token, "# "); + if (s->options & kPrintPrompt) + s->wp_conn->send(s->token, "# "); } void Terminal::Impl::printHelp(SessionContext *s) @@ -182,12 +203,17 @@ void Terminal::Impl::printHelp(SessionContext *s) "- !n Run the n command of history\r\n" "- !-n Run the last n command of history\r\n" "- !! Run last command\r\n" - "\r\n" - "Besides, UP,DOWN,LEFT,RIGHT,HOME,END,DELETE keys are available.\r\n" - "Try them.\r\n" - "\r\n" - ; + "\r\n"; s->wp_conn->send(s->token, help_str); + + if (s->options & kEnableEcho) { + const char *extra_str = \ + "Besides, UP,DOWN,LEFT,RIGHT,HOME,END,DELETE keys are available.\r\n" + "Try them.\r\n" + "\r\n" + ; + s->wp_conn->send(s->token, extra_str); + } } } diff --git a/terminal/impl/terminal.h b/terminal/impl/terminal.h index aa1590a..d39fb34 100644 --- a/terminal/impl/terminal.h +++ b/terminal/impl/terminal.h @@ -19,6 +19,9 @@ class Terminal::Impl { SessionToken newSession(Connection *wp_conn); bool deleteSession(const SessionToken &st); + uint32_t getOptions(const SessionToken &st) const; + void setOptions(const SessionToken &st, uint32_t options); + bool onBegin(const SessionToken &st); bool onExit(const SessionToken &st); diff --git a/terminal/impl/terminal_key_events.cpp b/terminal/impl/terminal_key_events.cpp index 588fe81..c050a07 100644 --- a/terminal/impl/terminal_key_events.cpp +++ b/terminal/impl/terminal_key_events.cpp @@ -21,26 +21,29 @@ namespace { void Terminal::Impl::onChar(SessionContext *s, char ch) { - s->wp_conn->send(s->token, ch); - if (s->cursor == s->curr_input.size()) s->curr_input.push_back(ch); else s->curr_input.insert(s->cursor, 1, ch); s->cursor++; - stringstream ss; - ss << s->curr_input.substr(s->cursor) - << string((s->curr_input.size() - s->cursor), '\b'); + if (s->options & kEnableEcho) { + s->wp_conn->send(s->token, ch); + + stringstream ss; + ss << s->curr_input.substr(s->cursor) + << string((s->curr_input.size() - s->cursor), '\b'); - auto refresh_str = ss.str(); - if (!refresh_str.empty()) - s->wp_conn->send(s->token, refresh_str); + auto refresh_str = ss.str(); + if (!refresh_str.empty()) + s->wp_conn->send(s->token, refresh_str); + } } void Terminal::Impl::onEnterKey(SessionContext *s) { - s->wp_conn->send(s->token, "\r\n"); + if (s->options & kEnableEcho) + s->wp_conn->send(s->token, "\r\n"); if (executeCmdline(s)) { s->history.push_back(s->curr_input); @@ -67,11 +70,13 @@ void Terminal::Impl::onBackspaceKey(SessionContext *s) s->cursor--; - stringstream ss; - ss << '\b' << s->curr_input.substr(s->cursor) << ' ' - << string((s->curr_input.size() - s->cursor + 1), '\b'); + if (s->options & kEnableEcho) { + stringstream ss; + ss << '\b' << s->curr_input.substr(s->cursor) << ' ' + << string((s->curr_input.size() - s->cursor + 1), '\b'); - s->wp_conn->send(s->token, ss.str()); + s->wp_conn->send(s->token, ss.str()); + } } void Terminal::Impl::onDeleteKey(SessionContext *s) @@ -81,11 +86,13 @@ void Terminal::Impl::onDeleteKey(SessionContext *s) s->curr_input.erase((s->cursor), 1); - stringstream ss; - ss << s->curr_input.substr(s->cursor) << ' ' - << string((s->curr_input.size() - s->cursor + 1), '\b'); + if (s->options & kEnableEcho) { + stringstream ss; + ss << s->curr_input.substr(s->cursor) << ' ' + << string((s->curr_input.size() - s->cursor + 1), '\b'); - s->wp_conn->send(s->token, ss.str()); + s->wp_conn->send(s->token, ss.str()); + } } void Terminal::Impl::onTabKey(SessionContext *s) diff --git a/terminal/terminal.cpp b/terminal/terminal.cpp index 25af299..907d20a 100644 --- a/terminal/terminal.cpp +++ b/terminal/terminal.cpp @@ -26,6 +26,16 @@ bool Terminal::deleteSession(const SessionToken &st) return impl_->deleteSession(st); } +uint32_t Terminal::getOptions(const SessionToken &st) const +{ + return impl_->getOptions(st); +} + +void Terminal::setOptions(const SessionToken &st, uint32_t options) +{ + impl_->setOptions(st, options); +} + bool Terminal::onBegin(const SessionToken &st) { return impl_->onBegin(st); diff --git a/terminal/terminal.h b/terminal/terminal.h index bec2e7b..4764218 100644 --- a/terminal/terminal.h +++ b/terminal/terminal.h @@ -16,6 +16,9 @@ class Terminal : public TerminalInteract, SessionToken newSession(Connection *wp_conn) override; bool deleteSession(const SessionToken &st) override; + uint32_t getOptions(const SessionToken &st) const override; + void setOptions(const SessionToken &st, uint32_t options) override; + bool onBegin(const SessionToken &st) override; bool onRecvString(const SessionToken &st, const std::string &str) override; bool onRecvWindowSize(const SessionToken &st, uint16_t w, uint16_t h) override; diff --git a/terminal/terminal_interact.h b/terminal/terminal_interact.h index bd12b91..26c7bb8 100644 --- a/terminal/terminal_interact.h +++ b/terminal/terminal_interact.h @@ -12,6 +12,14 @@ class TerminalInteract { virtual SessionToken newSession(Connection *wp_conn) = 0; virtual bool deleteSession(const SessionToken &st) = 0; + enum Option : uint32_t { + kEnableEcho = 0x01, + kPrintWelcome = 0x02, + kPrintPrompt = 0x04, + }; + virtual uint32_t getOptions(const SessionToken &st) const = 0; + virtual void setOptions(const SessionToken &st, uint32_t options) = 0; + virtual bool onBegin(const SessionToken &st) = 0; virtual bool onExit(const SessionToken &st) = 0; virtual bool onRecvString(const SessionToken &st, const std::string &str) = 0; -- Gitee From 831df20e138e172260850575b8cb1b613be242e9 Mon Sep 17 00:00:00 2001 From: Hevake Date: Sun, 6 Mar 2022 19:31:44 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E4=BF=AE=E6=94=B9terminal=EF=BC=8C?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=90=8C=E4=B8=80=E5=91=BD=E4=BB=A4=E8=A1=8C?= =?UTF-8?q?=E4=B8=AD=EF=BC=8C=E4=BB=A5=E5=88=86=E5=8F=B7=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E5=A4=9A=E5=91=BD=E4=BB=A4=E5=88=86=E9=9A=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- terminal/impl/terminal.h | 3 ++- terminal/impl/terminal_commands.cpp | 21 +++++++++++++++++---- terminal/impl/terminal_key_events.cpp | 2 +- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/terminal/impl/terminal.h b/terminal/impl/terminal.h index d39fb34..467d3e6 100644 --- a/terminal/impl/terminal.h +++ b/terminal/impl/terminal.h @@ -51,7 +51,8 @@ class Terminal::Impl { void printPrompt(SessionContext *s); void printHelp(SessionContext *s); - bool executeCmdline(SessionContext *s); + bool execute(SessionContext *s); + bool executeCmd(SessionContext *s, const std::string &cmdline); void executeCdCmd(SessionContext *s, const Args &args); void executeHelpCmd(SessionContext *s, const Args &args); diff --git a/terminal/impl/terminal_commands.cpp b/terminal/impl/terminal_commands.cpp index 4d0354e..c74af1f 100644 --- a/terminal/impl/terminal_commands.cpp +++ b/terminal/impl/terminal_commands.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "session_context.h" #include "dir_node.h" @@ -15,9 +16,21 @@ namespace tbox::terminal { using namespace std; -bool Terminal::Impl::executeCmdline(SessionContext *s) +bool Terminal::Impl::execute(SessionContext *s) +{ + std::vector cmdlines; + util::string::Split(s->curr_input, ";", cmdlines); + + for (auto &cmdline : cmdlines) { + if (!executeCmd(s, cmdline)) + return false; + } + + return true; +} + +bool Terminal::Impl::executeCmd(SessionContext *s, const std::string &cmdline) { - auto cmdline = s->curr_input; if (cmdline.empty()) return false; @@ -278,7 +291,7 @@ bool Terminal::Impl::executeRunHistoryCmd(SessionContext *s, const Args &args) string sub_cmd = args[0].substr(1); if (sub_cmd == "!") { s->curr_input = s->history.back(); - return executeCmdline(s); + return execute(s); } try { @@ -298,7 +311,7 @@ bool Terminal::Impl::executeRunHistoryCmd(SessionContext *s, const Args &args) if (is_index_valid) { s->wp_conn->send(s->token, s->curr_input + "\r\n"); - return executeCmdline(s); + return execute(s); } else s->wp_conn->send(s->token, "Error: index out of range\r\n"); } catch (const invalid_argument &e) { diff --git a/terminal/impl/terminal_key_events.cpp b/terminal/impl/terminal_key_events.cpp index c050a07..445c3c1 100644 --- a/terminal/impl/terminal_key_events.cpp +++ b/terminal/impl/terminal_key_events.cpp @@ -45,7 +45,7 @@ void Terminal::Impl::onEnterKey(SessionContext *s) if (s->options & kEnableEcho) s->wp_conn->send(s->token, "\r\n"); - if (executeCmdline(s)) { + if (execute(s)) { s->history.push_back(s->curr_input); if (s->history.size() > HISTORY_MAX_SIZE) s->history.pop_front(); -- Gitee From e45453ac75281f0a8388279b3263911d4d117518 Mon Sep 17 00:00:00 2001 From: Hevake Date: Sun, 6 Mar 2022 20:15:13 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=BA=86TcpRpc=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- terminal/Makefile | 6 +- .../example/{basic => tcp_rpc}/.gitignore | 0 terminal/example/{basic => tcp_rpc}/Makefile | 0 terminal/example/tcp_rpc/main.cpp | 147 ++++++++++++ terminal/example/telnetd/.gitignore | 1 + terminal/example/telnetd/Makefile | 17 ++ terminal/example/{basic => telnetd}/main.cpp | 2 +- terminal/impl/telnetd.h | 2 +- terminal/service/tcp_rpc.cpp | 226 ++++++++++++++++++ terminal/service/tcp_rpc.h | 30 +++ terminal/{ => service}/telnetd.cpp | 2 +- terminal/{ => service}/telnetd.h | 0 terminal/terminal_interact.h | 5 +- 13 files changed, 430 insertions(+), 8 deletions(-) rename terminal/example/{basic => tcp_rpc}/.gitignore (100%) rename terminal/example/{basic => tcp_rpc}/Makefile (100%) create mode 100644 terminal/example/tcp_rpc/main.cpp create mode 100644 terminal/example/telnetd/.gitignore create mode 100644 terminal/example/telnetd/Makefile rename terminal/example/{basic => telnetd}/main.cpp (99%) create mode 100644 terminal/service/tcp_rpc.cpp create mode 100644 terminal/service/tcp_rpc.h rename terminal/{ => service}/telnetd.cpp (94%) rename terminal/{ => service}/telnetd.h (100%) diff --git a/terminal/Makefile b/terminal/Makefile index 7e39803..9af7331 100644 --- a/terminal/Makefile +++ b/terminal/Makefile @@ -9,11 +9,11 @@ HEAD_FILES = \ terminal_interact.h \ terminal_nodes.h \ session.h \ - telnetd.h \ terminal.h \ + service/telnetd.h \ + service/tcp_rpc.h \ CPP_SRC_FILES = \ - telnetd.cpp \ terminal.cpp \ session.cpp \ impl/telnetd.cpp \ @@ -24,6 +24,8 @@ CPP_SRC_FILES = \ impl/key_event_scanner.cpp \ impl/dir_node.cpp \ impl/func_node.cpp \ + service/telnetd.cpp \ + service/tcp_rpc.cpp \ CXXFLAGS := -DLOG_MODULE_ID='"terminal"' $(CXXFLAGS) diff --git a/terminal/example/basic/.gitignore b/terminal/example/tcp_rpc/.gitignore similarity index 100% rename from terminal/example/basic/.gitignore rename to terminal/example/tcp_rpc/.gitignore diff --git a/terminal/example/basic/Makefile b/terminal/example/tcp_rpc/Makefile similarity index 100% rename from terminal/example/basic/Makefile rename to terminal/example/tcp_rpc/Makefile diff --git a/terminal/example/tcp_rpc/main.cpp b/terminal/example/tcp_rpc/main.cpp new file mode 100644 index 0000000..13815ac --- /dev/null +++ b/terminal/example/tcp_rpc/main.cpp @@ -0,0 +1,147 @@ +#include + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +using namespace tbox; +using namespace tbox::event; +using namespace tbox::terminal; + +void BuildNodes(TerminalNodes &term, Loop *wp_loop); + +int main(int argc, char **argv) +{ + std::string bind_addr = "0.0.0.0:12345"; + if (argc >= 2) + bind_addr = argv[1]; + + LogOutput_Initialize(argv[0]); + + auto sp_loop = Loop::New(); + SetScopeExitAction([sp_loop] { delete sp_loop; }); + + Terminal term; + TcpRpc rpc(sp_loop, &term); + if (!rpc.initialize(bind_addr)) { + std::cout << "Error: rpc init fail" << std::endl; + return 0; + } + + //! 注册ctrl+C停止信号 + auto *sp_stop_ev = sp_loop->newSignalEvent(); + SetScopeExitAction([sp_stop_ev] { delete sp_stop_ev; }); + sp_stop_ev->initialize(std::set{SIGINT,SIGTERM}, Event::Mode::kOneshot); + //! 指定ctrl+C时要做的事务 + sp_stop_ev->setCallback( + [&] (int) { + rpc.stop(); + sp_loop->exitLoop(); //! (3) 退出事件循环 + } + ); + sp_stop_ev->enable(); + + BuildNodes(term, sp_loop); + + rpc.start(); + + LogInfo("Start"); + sp_loop->runLoop(Loop::Mode::kForever); + LogInfo("Stoped"); + + return 0; +} + +void BuildNodes(TerminalNodes &term, Loop *wp_loop) +{ + /** + * sync_func 就是同步执行的命令函数 + * 当他被执行时,只需要调用 Session 的 send() 方法就可以输出信息到终端 + */ + Func sync_func = \ + [](const Session &s, const Args &args) { + std::stringstream ss; + ss << "This is sync_func.\r\nArgs:\r\n"; + for (size_t i = 0; i < args.size(); ++i) + ss << '[' << i << "]: " << args.at(i) << "\r\n"; + s.send(ss.str()); + }; + + /** + * async_func 是异步执行的命令函数 + * 它的结果打印会在命令函数执行完成之后, + * + * 这种情冲常用于异步事件中,比如某命令的动作是发送HTTP请求,将请求的结果打印出来 + * 执行命令时,命令只是发出请求就结束。而结果则是在后面则到返回结果,或检测到异常 + * 时才会输出。 + */ + Func async_func = \ + [=](const Session &s, const Args &args) { + if (args.size() < 2) { + s.send(std::string("Usage: ") + args[0] + " \r\n"); + return; + } + + auto name = args[1]; + //! 创建一个定时器,令其每秒打印 + auto sp_timer = wp_loop->newTimerEvent(); + sp_timer->initialize(std::chrono::seconds(1), Event::Mode::kPersist); + sp_timer->setCallback( + [=] { //! 注意:这里用的是 =,而不是 & 。用意是捕获 s 的副本,而不是引用它。 + if (!s.isValid()) { //! 可以检查 s 对应的 Session 是否有效,如果无效则可以不做任何事情 + sp_timer->disable(); + wp_loop->run([sp_timer] { delete sp_timer; }); + return; + } + s.send(std::string("timer ") + name + " timeout\r\n"); + } + ); + sp_timer->enable(); + s.send(std::string("timer ") + name + " start\r\n"); + }; + +/** +构建如下结点树: +|-- dir1 +| |-- dir1_1 +| | |-- async* +| | `-- root(R) +| `-- dir1_2 +| `-- sync* +|-- dir2 +`-- sync* +*/ + auto sync_func_token = term.createFuncNode(sync_func, "This is sync func"); + auto async_func_token = term.createFuncNode(async_func, "This is async func"); + + auto dir1_token = term.createDirNode("This is dir1"); + auto dir2_token = term.createDirNode(); + + auto dir1_1_token = term.createDirNode(); + auto dir1_2_token = term.createDirNode(); + + term.mountNode(dir1_1_token, async_func_token, "async"); + term.mountNode(dir1_2_token, sync_func_token, "sync"); + + term.mountNode(dir1_token, dir1_1_token, "dir1_1"); + term.mountNode(dir1_token, dir1_2_token, "dir1_2"); + + term.mountNode(term.rootNode(), sync_func_token, "sync"); + term.mountNode(term.rootNode(), dir1_token, "dir1"); + term.mountNode(term.rootNode(), dir2_token, "dir2"); + + term.mountNode(dir1_1_token, term.rootNode(), "root"); //! 循环引用 +} diff --git a/terminal/example/telnetd/.gitignore b/terminal/example/telnetd/.gitignore new file mode 100644 index 0000000..69ff739 --- /dev/null +++ b/terminal/example/telnetd/.gitignore @@ -0,0 +1 @@ +/demo diff --git a/terminal/example/telnetd/Makefile b/terminal/example/telnetd/Makefile new file mode 100644 index 0000000..bb4d9fa --- /dev/null +++ b/terminal/example/telnetd/Makefile @@ -0,0 +1,17 @@ +include ../build_env.mk + +TARGET := demo +OBJECTS := main.o +CXXFLAGS += -ggdb -DLOG_MODULE_ID='"demo"' +LDFLAGS += -L.. -ltbox_terminal -ltbox_util -ltbox_network -ltbox_event -ltbox_base -lpthread + +CXXFLAGS += -fsanitize=address -fno-omit-frame-pointer +LDFLAGS += -fsanitize=address -static-libasan + +all : $(TARGET) + +$(TARGET) : $(OBJECTS) + $(CXX) -o $@ $^ $(LDFLAGS) + +clean: + rm -rf $(OBJECTS) diff --git a/terminal/example/basic/main.cpp b/terminal/example/telnetd/main.cpp similarity index 99% rename from terminal/example/basic/main.cpp rename to terminal/example/telnetd/main.cpp index 960410f..907d8fa 100644 --- a/terminal/example/basic/main.cpp +++ b/terminal/example/telnetd/main.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include using namespace tbox; diff --git a/terminal/impl/telnetd.h b/terminal/impl/telnetd.h index 8f5b27a..5b52cd2 100644 --- a/terminal/impl/telnetd.h +++ b/terminal/impl/telnetd.h @@ -5,7 +5,7 @@ #include -#include "../telnetd.h" +#include "../service/telnetd.h" #include "../connection.h" namespace tbox::terminal { diff --git a/terminal/service/tcp_rpc.cpp b/terminal/service/tcp_rpc.cpp new file mode 100644 index 0000000..b8eb69a --- /dev/null +++ b/terminal/service/tcp_rpc.cpp @@ -0,0 +1,226 @@ +#include "tcp_rpc.h" + +#include +#include +#include + +#include +#include +#include + +#include "../service/telnetd.h" +#include "../connection.h" +#include "../terminal_interact.h" + +namespace tbox { +namespace terminal { + +using namespace std; +using namespace std::placeholders; +using namespace event; +using namespace network; +using namespace util; + +class TcpRpc::Impl : public Connection { + public: + Impl(Loop *wp_loop, TerminalInteract *wp_terminal); + virtual ~Impl(); + + public: + bool initialize(const std::string &bind_addr); + bool start(); + void stop(); + void cleanup(); + + public: + bool send(const SessionToken &st, char ch) override; + bool send(const SessionToken &st, const std::string &str) override; + bool endSession(const SessionToken &st) override; + bool isValid(const SessionToken &st) const override; + + protected: + bool send(const TcpServer::ClientToken &ct, const void *data_ptr, size_t data_size); + + void onTcpConnected(const TcpServer::ClientToken &ct); + void onTcpDisconnected(const TcpServer::ClientToken &ct); + void onTcpReceived(const TcpServer::ClientToken &ct, Buffer &buff); + void onRecvString(const TcpServer::ClientToken &ct, const std::string &str); + + private: + Loop *wp_loop_ = nullptr; + TerminalInteract *wp_terminal_ = nullptr; + TcpServer *sp_tcp_ = nullptr; + + map session_to_client_; + map client_to_session_; +}; + +TcpRpc::TcpRpc(event::Loop *wp_loop, TerminalInteract *wp_terminal) : + impl_(new Impl(wp_loop, wp_terminal)) +{ + assert(impl_ != nullptr); +} + +TcpRpc::~TcpRpc() +{ + delete impl_; +} + +bool TcpRpc::initialize(const std::string &bind_addr) +{ + return impl_->initialize(bind_addr); +} + +bool TcpRpc::start() +{ + return impl_->start(); +} + +void TcpRpc::stop() +{ + return impl_->stop(); +} + +void TcpRpc::cleanup() +{ + return impl_->cleanup(); +} + +//////////////////////////////////////////////////// +// +//////////////////////////////////////////////////// + +TcpRpc::Impl::Impl(event::Loop *wp_loop, TerminalInteract *wp_terminal) : + wp_loop_(wp_loop), + wp_terminal_(wp_terminal), + sp_tcp_(new TcpServer(wp_loop)) +{ + assert(wp_loop_ != nullptr); + assert(wp_terminal_ != nullptr); + assert(sp_tcp_ != nullptr); +} + +TcpRpc::Impl::~Impl() +{ + delete sp_tcp_; +} + +bool TcpRpc::Impl::initialize(const std::string &bind_addr_str) +{ + auto bind_addr = SockAddr::FromString(bind_addr_str); + if (!sp_tcp_->initialize(bind_addr)) + return false; + + sp_tcp_->setConnectedCallback(std::bind(&Impl::onTcpConnected, this, _1)); + sp_tcp_->setReceiveCallback(std::bind(&Impl::onTcpReceived, this, _1, _2), 0); + sp_tcp_->setDisconnectedCallback(std::bind(&Impl::onTcpDisconnected, this, _1)); + return true; +} + +bool TcpRpc::Impl::start() +{ + return sp_tcp_->start(); +} + +void TcpRpc::Impl::stop() +{ + sp_tcp_->stop(); +} + +void TcpRpc::Impl::cleanup() +{ + sp_tcp_->cleanup(); +} + +bool TcpRpc::Impl::send(const SessionToken &st, const std::string &str) +{ + auto ct = session_to_client_.at(st); + if (st.isNull()) + return false; + + send(ct, str.c_str(), str.size()); + return true; +} + +bool TcpRpc::Impl::send(const SessionToken &st, char ch) +{ + auto ct = session_to_client_.at(st); + if (st.isNull()) + return false; + + send(ct, &ch, 1); + return true; +} + +bool TcpRpc::Impl::endSession(const SessionToken &st) +{ + auto ct = session_to_client_.at(st); + if (ct.isNull()) + return false; + + //! 委托执行,否则会出自我销毁的异常 + wp_loop_->run( + [this, st, ct] { + client_to_session_.erase(ct); + session_to_client_.erase(st); + sp_tcp_->disconnect(ct); + } + ); + + return true; +} + +bool TcpRpc::Impl::isValid(const SessionToken &st) const +{ + return session_to_client_.find(st) != session_to_client_.end(); +} + +void TcpRpc::Impl::onTcpConnected(const TcpServer::ClientToken &ct) +{ + cout << ct.id() << " connected" << endl; + + auto st = wp_terminal_->newSession(this); + client_to_session_[ct] = st; + session_to_client_[st] = ct; + + wp_terminal_->onBegin(st); +} + +void TcpRpc::Impl::onTcpDisconnected(const TcpServer::ClientToken &ct) +{ + cout << ct.id() << " disconnected" << endl; + + auto st = client_to_session_.at(ct); + client_to_session_.erase(ct); + session_to_client_.erase(st); + wp_terminal_->deleteSession(st); +} + +bool TcpRpc::Impl::send(const TcpServer::ClientToken &ct, const void *data_ptr, size_t data_size) +{ +#if 1 + auto hex_str = string::RawDataToHexStr(data_ptr, data_size); + cout << ct.id() << " << send " << data_size << ": " << hex_str << endl; +#endif + return sp_tcp_->send(ct, data_ptr, data_size); +} + +void TcpRpc::Impl::onTcpReceived(const TcpServer::ClientToken &ct, Buffer &buff) +{ +#if 1 + auto hex_str = string::RawDataToHexStr(buff.readableBegin(), buff.readableSize()); + cout << ct.id() << " >> recv " << buff.readableSize() << ": " << hex_str << endl; +#endif + + onRecvString(ct, std::string(reinterpret_cast(buff.readableBegin()), buff.readableSize())); + buff.hasReadAll(); +} + +void TcpRpc::Impl::onRecvString(const TcpServer::ClientToken &ct, const std::string &str) +{ + auto st = client_to_session_.at(ct); + wp_terminal_->onRecvString(st, str); +} + +} +} diff --git a/terminal/service/tcp_rpc.h b/terminal/service/tcp_rpc.h new file mode 100644 index 0000000..daee58d --- /dev/null +++ b/terminal/service/tcp_rpc.h @@ -0,0 +1,30 @@ +#ifndef TBOX_TERMINAL_TCP_RPC_H_20220127 +#define TBOX_TERMINAL_TCP_RPC_H_20220127 + +#include + +namespace tbox { +namespace terminal { + +class TerminalInteract; + +class TcpRpc { + public: + TcpRpc(event::Loop *wp_loop, TerminalInteract *wp_terminal); + ~TcpRpc(); + + public: + bool initialize(const std::string &bind_addr); + bool start(); + void stop(); + void cleanup(); + + private: + class Impl; + Impl *impl_ = nullptr; +}; + +} +} + +#endif //TBOX_TERMINAL_TCP_RPC_H_20220127 diff --git a/terminal/telnetd.cpp b/terminal/service/telnetd.cpp similarity index 94% rename from terminal/telnetd.cpp rename to terminal/service/telnetd.cpp index dfa950a..7402456 100644 --- a/terminal/telnetd.cpp +++ b/terminal/service/telnetd.cpp @@ -1,5 +1,5 @@ #include "telnetd.h" -#include "impl/telnetd.h" +#include "../impl/telnetd.h" namespace tbox::terminal { diff --git a/terminal/telnetd.h b/terminal/service/telnetd.h similarity index 100% rename from terminal/telnetd.h rename to terminal/service/telnetd.h diff --git a/terminal/terminal_interact.h b/terminal/terminal_interact.h index 26c7bb8..14a013f 100644 --- a/terminal/terminal_interact.h +++ b/terminal/terminal_interact.h @@ -13,9 +13,8 @@ class TerminalInteract { virtual bool deleteSession(const SessionToken &st) = 0; enum Option : uint32_t { - kEnableEcho = 0x01, - kPrintWelcome = 0x02, - kPrintPrompt = 0x04, + kEnableEcho = 0x01, + kQuietMode = 0x02, }; virtual uint32_t getOptions(const SessionToken &st) const = 0; virtual void setOptions(const SessionToken &st, uint32_t options) = 0; -- Gitee From 0531165b7eca0f9233a639b863105a733d235275 Mon Sep 17 00:00:00 2001 From: Hevake Date: Sun, 6 Mar 2022 20:57:55 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=BA=86TcpRpc=E7=9A=84?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=B9=B6=E5=B0=86=E5=AE=83=E9=9B=86?= =?UTF-8?q?=E6=88=90=E5=88=B0main=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/context_imp.cpp | 21 ++- main/context_imp.h | 5 +- terminal/Makefile | 7 +- terminal/impl/service/tcp_rpc.cpp | 136 +++++++++++++++++ terminal/impl/service/tcp_rpc.h | 57 +++++++ terminal/impl/{ => service}/telnetd.cpp | 3 +- terminal/impl/{ => service}/telnetd.h | 4 +- terminal/impl/terminal.cpp | 4 +- terminal/impl/terminal_commands.cpp | 3 +- terminal/service/tcp_rpc.cpp | 189 +----------------------- terminal/service/tcp_rpc.h | 6 +- terminal/service/telnetd.cpp | 2 +- terminal/terminal_interact.h | 2 +- 13 files changed, 234 insertions(+), 205 deletions(-) create mode 100644 terminal/impl/service/tcp_rpc.cpp create mode 100644 terminal/impl/service/tcp_rpc.h rename terminal/impl/{ => service}/telnetd.cpp (98%) rename terminal/impl/{ => service}/telnetd.h (97%) diff --git a/main/context_imp.cpp b/main/context_imp.cpp index 3815485..0a092e4 100644 --- a/main/context_imp.cpp +++ b/main/context_imp.cpp @@ -15,17 +15,20 @@ ContextImp::ContextImp() : sp_thread_pool_(new eventx::ThreadPool(sp_loop_)), sp_timer_pool_(new eventx::TimerPool(sp_loop_)), sp_terminal_(new terminal::Terminal), - sp_telnetd_(new terminal::Telnetd(sp_loop_, sp_terminal_)) + sp_telnetd_(new terminal::Telnetd(sp_loop_, sp_terminal_)), + sp_tcp_rpc_(new terminal::TcpRpc(sp_loop_, sp_terminal_)) { assert(sp_loop_ != nullptr); assert(sp_thread_pool_ != nullptr); assert(sp_timer_pool_ != nullptr); assert(sp_terminal_ != nullptr); assert(sp_telnetd_ != nullptr); + assert(sp_tcp_rpc_ != nullptr); } ContextImp::~ContextImp() { + delete sp_tcp_rpc_; delete sp_telnetd_; delete sp_terminal_; delete sp_timer_pool_; @@ -64,6 +67,14 @@ bool ContextImp::initialize(const Json &cfg) telnetd_init_ok = true; } } + if (cfg.contains("tcp_rpc")) { + auto &js_tcp_rpc = cfg["tcp_rpc"]; + if (js_tcp_rpc.contains("bind")) { + auto &js_tcp_rpc_bind = js_tcp_rpc["bind"]; + if (sp_tcp_rpc_->initialize(js_tcp_rpc_bind.get())) + tcp_rpc_init_ok = true; + } + } buildTerminalNodes(); @@ -74,17 +85,25 @@ bool ContextImp::start() { if (telnetd_init_ok) sp_telnetd_->start(); + + if (tcp_rpc_init_ok) + sp_tcp_rpc_->start(); + return true; } void ContextImp::stop() { + if (tcp_rpc_init_ok) + sp_tcp_rpc_->stop(); + if (telnetd_init_ok) sp_telnetd_->stop(); } void ContextImp::cleanup() { + sp_tcp_rpc_->cleanup(); sp_telnetd_->cleanup(); sp_timer_pool_->cleanup(); sp_thread_pool_->cleanup(); diff --git a/main/context_imp.h b/main/context_imp.h index a19c76c..a414c19 100644 --- a/main/context_imp.h +++ b/main/context_imp.h @@ -5,7 +5,8 @@ #include #include -#include +#include +#include namespace tbox::main { @@ -38,7 +39,9 @@ class ContextImp : public Context { terminal::Terminal *sp_terminal_ = nullptr; terminal::Telnetd *sp_telnetd_ = nullptr; + terminal::TcpRpc *sp_tcp_rpc_ = nullptr; bool telnetd_init_ok = false; + bool tcp_rpc_init_ok = false; }; } diff --git a/terminal/Makefile b/terminal/Makefile index 9af7331..b80a700 100644 --- a/terminal/Makefile +++ b/terminal/Makefile @@ -16,7 +16,8 @@ HEAD_FILES = \ CPP_SRC_FILES = \ terminal.cpp \ session.cpp \ - impl/telnetd.cpp \ + service/telnetd.cpp \ + service/tcp_rpc.cpp \ impl/terminal.cpp \ impl/terminal_key_events.cpp \ impl/terminal_commands.cpp \ @@ -24,8 +25,8 @@ CPP_SRC_FILES = \ impl/key_event_scanner.cpp \ impl/dir_node.cpp \ impl/func_node.cpp \ - service/telnetd.cpp \ - service/tcp_rpc.cpp \ + impl/service/telnetd.cpp \ + impl/service/tcp_rpc.cpp \ CXXFLAGS := -DLOG_MODULE_ID='"terminal"' $(CXXFLAGS) diff --git a/terminal/impl/service/tcp_rpc.cpp b/terminal/impl/service/tcp_rpc.cpp new file mode 100644 index 0000000..b77d859 --- /dev/null +++ b/terminal/impl/service/tcp_rpc.cpp @@ -0,0 +1,136 @@ +#include "tcp_rpc.h" + +#include +#include + +#include + +namespace tbox { +namespace terminal { + +TcpRpc::Impl::Impl(event::Loop *wp_loop, TerminalInteract *wp_terminal) : + wp_loop_(wp_loop), + wp_terminal_(wp_terminal), + sp_tcp_(new TcpServer(wp_loop)) +{ + assert(wp_loop_ != nullptr); + assert(wp_terminal_ != nullptr); + assert(sp_tcp_ != nullptr); +} + +TcpRpc::Impl::~Impl() +{ + delete sp_tcp_; +} + +bool TcpRpc::Impl::initialize(const std::string &bind_addr_str) +{ + auto bind_addr = SockAddr::FromString(bind_addr_str); + if (!sp_tcp_->initialize(bind_addr)) + return false; + + sp_tcp_->setConnectedCallback(std::bind(&Impl::onTcpConnected, this, _1)); + sp_tcp_->setReceiveCallback(std::bind(&Impl::onTcpReceived, this, _1, _2), 0); + sp_tcp_->setDisconnectedCallback(std::bind(&Impl::onTcpDisconnected, this, _1)); + return true; +} + +bool TcpRpc::Impl::start() +{ + return sp_tcp_->start(); +} + +void TcpRpc::Impl::stop() +{ + sp_tcp_->stop(); +} + +void TcpRpc::Impl::cleanup() +{ + sp_tcp_->cleanup(); +} + +bool TcpRpc::Impl::send(const SessionToken &st, const std::string &str) +{ + auto ct = session_to_client_.at(st); + if (st.isNull()) + return false; + + send(ct, str.c_str(), str.size()); + return true; +} + +bool TcpRpc::Impl::send(const SessionToken &st, char ch) +{ + auto ct = session_to_client_.at(st); + if (st.isNull()) + return false; + + send(ct, &ch, 1); + return true; +} + +bool TcpRpc::Impl::endSession(const SessionToken &st) +{ + auto ct = session_to_client_.at(st); + if (ct.isNull()) + return false; + + //! 委托执行,否则会出自我销毁的异常 + wp_loop_->run( + [this, st, ct] { + client_to_session_.erase(ct); + session_to_client_.erase(st); + sp_tcp_->disconnect(ct); + } + ); + + return true; +} + +bool TcpRpc::Impl::isValid(const SessionToken &st) const +{ + return session_to_client_.find(st) != session_to_client_.end(); +} + +void TcpRpc::Impl::onTcpConnected(const TcpServer::ClientToken &ct) +{ + cout << ct.id() << " connected" << endl; + + auto st = wp_terminal_->newSession(this); + client_to_session_[ct] = st; + session_to_client_[st] = ct; + + wp_terminal_->setOptions(st, TerminalInteract::kQuietMode); + wp_terminal_->onBegin(st); +} + +void TcpRpc::Impl::onTcpDisconnected(const TcpServer::ClientToken &ct) +{ + cout << ct.id() << " disconnected" << endl; + + auto st = client_to_session_.at(ct); + client_to_session_.erase(ct); + session_to_client_.erase(st); + wp_terminal_->deleteSession(st); +} + +bool TcpRpc::Impl::send(const TcpServer::ClientToken &ct, const void *data_ptr, size_t data_size) +{ + return sp_tcp_->send(ct, data_ptr, data_size); +} + +void TcpRpc::Impl::onTcpReceived(const TcpServer::ClientToken &ct, Buffer &buff) +{ + onRecvString(ct, std::string(reinterpret_cast(buff.readableBegin()), buff.readableSize())); + buff.hasReadAll(); +} + +void TcpRpc::Impl::onRecvString(const TcpServer::ClientToken &ct, const std::string &str) +{ + auto st = client_to_session_.at(ct); + wp_terminal_->onRecvString(st, str); +} + +} +} diff --git a/terminal/impl/service/tcp_rpc.h b/terminal/impl/service/tcp_rpc.h new file mode 100644 index 0000000..3c01a99 --- /dev/null +++ b/terminal/impl/service/tcp_rpc.h @@ -0,0 +1,57 @@ +#ifndef TBOX_TERMINAL_TCP_RPC_IMP_H_20220306 +#define TBOX_TERMINAL_TCP_RPC_IMP_H_20220306 + +#include + +#include + +#include "../../connection.h" +#include "../../service/tcp_rpc.h" +#include "../../terminal_interact.h" + +namespace tbox { +namespace terminal { + +using namespace std; +using namespace std::placeholders; +using namespace event; +using namespace network; + +class TcpRpc::Impl : Connection { + public: + Impl(Loop *wp_loop, TerminalInteract *wp_terminal); + virtual ~Impl(); + + public: + bool initialize(const std::string &bind_addr); + bool start(); + void stop(); + void cleanup(); + + public: + bool send(const SessionToken &st, char ch) override; + bool send(const SessionToken &st, const std::string &str) override; + bool endSession(const SessionToken &st) override; + bool isValid(const SessionToken &st) const override; + + protected: + bool send(const TcpServer::ClientToken &ct, const void *data_ptr, size_t data_size); + + void onTcpConnected(const TcpServer::ClientToken &ct); + void onTcpDisconnected(const TcpServer::ClientToken &ct); + void onTcpReceived(const TcpServer::ClientToken &ct, Buffer &buff); + void onRecvString(const TcpServer::ClientToken &ct, const std::string &str); + + private: + Loop *wp_loop_ = nullptr; + TerminalInteract *wp_terminal_ = nullptr; + TcpServer *sp_tcp_ = nullptr; + + map session_to_client_; + map client_to_session_; +}; + +} +} + +#endif //TBOX_TERMINAL_TCP_RPC_IMP_H_20220306 diff --git a/terminal/impl/telnetd.cpp b/terminal/impl/service/telnetd.cpp similarity index 98% rename from terminal/impl/telnetd.cpp rename to terminal/impl/service/telnetd.cpp index 75f4fa4..0749ae8 100644 --- a/terminal/impl/telnetd.cpp +++ b/terminal/impl/service/telnetd.cpp @@ -6,7 +6,7 @@ #include #include -#include "../terminal_interact.h" +#include "../../terminal_interact.h" namespace tbox::terminal { @@ -113,7 +113,6 @@ void Telnetd::Impl::onTcpConnected(const TcpServer::ClientToken &ct) sendNego(ct, kWILL, kECHO); sendNego(ct, kWILL, kSGA); - wp_terminal_->setOptions(st, TerminalInteract::kPrintWelcome | TerminalInteract::kPrintPrompt); wp_terminal_->onBegin(st); } diff --git a/terminal/impl/telnetd.h b/terminal/impl/service/telnetd.h similarity index 97% rename from terminal/impl/telnetd.h rename to terminal/impl/service/telnetd.h index 5b52cd2..85b2a7a 100644 --- a/terminal/impl/telnetd.h +++ b/terminal/impl/service/telnetd.h @@ -5,8 +5,8 @@ #include -#include "../service/telnetd.h" -#include "../connection.h" +#include "../../service/telnetd.h" +#include "../../connection.h" namespace tbox::terminal { diff --git a/terminal/impl/terminal.cpp b/terminal/impl/terminal.cpp index 308baa8..0a39679 100644 --- a/terminal/impl/terminal.cpp +++ b/terminal/impl/terminal.cpp @@ -78,7 +78,7 @@ bool Terminal::Impl::onBegin(const SessionToken &st) if (s == nullptr) return false; - if (s->options & kPrintWelcome) { + if (!(s->options & kQuietMode)) { s->wp_conn->send(st, "\r\n" "Welcome to CppTBox Terminal.\r\n" @@ -181,7 +181,7 @@ bool Terminal::Impl::onRecvWindowSize(const SessionToken &st, uint16_t w, uint16 void Terminal::Impl::printPrompt(SessionContext *s) { - if (s->options & kPrintPrompt) + if (!(s->options & kQuietMode)) s->wp_conn->send(s->token, "# "); } diff --git a/terminal/impl/terminal_commands.cpp b/terminal/impl/terminal_commands.cpp index c74af1f..10d5cff 100644 --- a/terminal/impl/terminal_commands.cpp +++ b/terminal/impl/terminal_commands.cpp @@ -163,7 +163,8 @@ void Terminal::Impl::executeHistoryCmd(SessionContext *s, const Args &args) void Terminal::Impl::executeExitCmd(SessionContext *s, const Args &args) { - s->wp_conn->send(s->token, "Bye!\r\n"); + if (!(s->options & kQuietMode)) + s->wp_conn->send(s->token, "Bye!\r\n"); s->wp_conn->endSession(s->token); } diff --git a/terminal/service/tcp_rpc.cpp b/terminal/service/tcp_rpc.cpp index b8eb69a..fda6e7b 100644 --- a/terminal/service/tcp_rpc.cpp +++ b/terminal/service/tcp_rpc.cpp @@ -1,60 +1,9 @@ #include "tcp_rpc.h" - -#include -#include -#include - -#include -#include -#include - -#include "../service/telnetd.h" -#include "../connection.h" -#include "../terminal_interact.h" +#include "../impl/service/tcp_rpc.h" namespace tbox { namespace terminal { -using namespace std; -using namespace std::placeholders; -using namespace event; -using namespace network; -using namespace util; - -class TcpRpc::Impl : public Connection { - public: - Impl(Loop *wp_loop, TerminalInteract *wp_terminal); - virtual ~Impl(); - - public: - bool initialize(const std::string &bind_addr); - bool start(); - void stop(); - void cleanup(); - - public: - bool send(const SessionToken &st, char ch) override; - bool send(const SessionToken &st, const std::string &str) override; - bool endSession(const SessionToken &st) override; - bool isValid(const SessionToken &st) const override; - - protected: - bool send(const TcpServer::ClientToken &ct, const void *data_ptr, size_t data_size); - - void onTcpConnected(const TcpServer::ClientToken &ct); - void onTcpDisconnected(const TcpServer::ClientToken &ct); - void onTcpReceived(const TcpServer::ClientToken &ct, Buffer &buff); - void onRecvString(const TcpServer::ClientToken &ct, const std::string &str); - - private: - Loop *wp_loop_ = nullptr; - TerminalInteract *wp_terminal_ = nullptr; - TcpServer *sp_tcp_ = nullptr; - - map session_to_client_; - map client_to_session_; -}; - TcpRpc::TcpRpc(event::Loop *wp_loop, TerminalInteract *wp_terminal) : impl_(new Impl(wp_loop, wp_terminal)) { @@ -86,141 +35,5 @@ void TcpRpc::cleanup() return impl_->cleanup(); } -//////////////////////////////////////////////////// -// -//////////////////////////////////////////////////// - -TcpRpc::Impl::Impl(event::Loop *wp_loop, TerminalInteract *wp_terminal) : - wp_loop_(wp_loop), - wp_terminal_(wp_terminal), - sp_tcp_(new TcpServer(wp_loop)) -{ - assert(wp_loop_ != nullptr); - assert(wp_terminal_ != nullptr); - assert(sp_tcp_ != nullptr); -} - -TcpRpc::Impl::~Impl() -{ - delete sp_tcp_; -} - -bool TcpRpc::Impl::initialize(const std::string &bind_addr_str) -{ - auto bind_addr = SockAddr::FromString(bind_addr_str); - if (!sp_tcp_->initialize(bind_addr)) - return false; - - sp_tcp_->setConnectedCallback(std::bind(&Impl::onTcpConnected, this, _1)); - sp_tcp_->setReceiveCallback(std::bind(&Impl::onTcpReceived, this, _1, _2), 0); - sp_tcp_->setDisconnectedCallback(std::bind(&Impl::onTcpDisconnected, this, _1)); - return true; -} - -bool TcpRpc::Impl::start() -{ - return sp_tcp_->start(); -} - -void TcpRpc::Impl::stop() -{ - sp_tcp_->stop(); -} - -void TcpRpc::Impl::cleanup() -{ - sp_tcp_->cleanup(); -} - -bool TcpRpc::Impl::send(const SessionToken &st, const std::string &str) -{ - auto ct = session_to_client_.at(st); - if (st.isNull()) - return false; - - send(ct, str.c_str(), str.size()); - return true; -} - -bool TcpRpc::Impl::send(const SessionToken &st, char ch) -{ - auto ct = session_to_client_.at(st); - if (st.isNull()) - return false; - - send(ct, &ch, 1); - return true; -} - -bool TcpRpc::Impl::endSession(const SessionToken &st) -{ - auto ct = session_to_client_.at(st); - if (ct.isNull()) - return false; - - //! 委托执行,否则会出自我销毁的异常 - wp_loop_->run( - [this, st, ct] { - client_to_session_.erase(ct); - session_to_client_.erase(st); - sp_tcp_->disconnect(ct); - } - ); - - return true; -} - -bool TcpRpc::Impl::isValid(const SessionToken &st) const -{ - return session_to_client_.find(st) != session_to_client_.end(); -} - -void TcpRpc::Impl::onTcpConnected(const TcpServer::ClientToken &ct) -{ - cout << ct.id() << " connected" << endl; - - auto st = wp_terminal_->newSession(this); - client_to_session_[ct] = st; - session_to_client_[st] = ct; - - wp_terminal_->onBegin(st); -} - -void TcpRpc::Impl::onTcpDisconnected(const TcpServer::ClientToken &ct) -{ - cout << ct.id() << " disconnected" << endl; - - auto st = client_to_session_.at(ct); - client_to_session_.erase(ct); - session_to_client_.erase(st); - wp_terminal_->deleteSession(st); -} - -bool TcpRpc::Impl::send(const TcpServer::ClientToken &ct, const void *data_ptr, size_t data_size) -{ -#if 1 - auto hex_str = string::RawDataToHexStr(data_ptr, data_size); - cout << ct.id() << " << send " << data_size << ": " << hex_str << endl; -#endif - return sp_tcp_->send(ct, data_ptr, data_size); -} - -void TcpRpc::Impl::onTcpReceived(const TcpServer::ClientToken &ct, Buffer &buff) -{ -#if 1 - auto hex_str = string::RawDataToHexStr(buff.readableBegin(), buff.readableSize()); - cout << ct.id() << " >> recv " << buff.readableSize() << ": " << hex_str << endl; -#endif - - onRecvString(ct, std::string(reinterpret_cast(buff.readableBegin()), buff.readableSize())); - buff.hasReadAll(); -} - -void TcpRpc::Impl::onRecvString(const TcpServer::ClientToken &ct, const std::string &str) -{ - auto st = client_to_session_.at(ct); - wp_terminal_->onRecvString(st, str); -} - } } diff --git a/terminal/service/tcp_rpc.h b/terminal/service/tcp_rpc.h index daee58d..e2776d5 100644 --- a/terminal/service/tcp_rpc.h +++ b/terminal/service/tcp_rpc.h @@ -1,5 +1,5 @@ -#ifndef TBOX_TERMINAL_TCP_RPC_H_20220127 -#define TBOX_TERMINAL_TCP_RPC_H_20220127 +#ifndef TBOX_TERMINAL_TCP_RPC_H_20220306 +#define TBOX_TERMINAL_TCP_RPC_H_20220306 #include @@ -27,4 +27,4 @@ class TcpRpc { } } -#endif //TBOX_TERMINAL_TCP_RPC_H_20220127 +#endif //TBOX_TERMINAL_TCP_RPC_H_20220306 diff --git a/terminal/service/telnetd.cpp b/terminal/service/telnetd.cpp index 7402456..df67ed8 100644 --- a/terminal/service/telnetd.cpp +++ b/terminal/service/telnetd.cpp @@ -1,5 +1,5 @@ #include "telnetd.h" -#include "../impl/telnetd.h" +#include "../impl/service/telnetd.h" namespace tbox::terminal { diff --git a/terminal/terminal_interact.h b/terminal/terminal_interact.h index 14a013f..18700fc 100644 --- a/terminal/terminal_interact.h +++ b/terminal/terminal_interact.h @@ -14,7 +14,7 @@ class TerminalInteract { enum Option : uint32_t { kEnableEcho = 0x01, - kQuietMode = 0x02, + kQuietMode = 0x02, //! 安静模式,不主动打印提示信息 }; virtual uint32_t getOptions(const SessionToken &st) const = 0; virtual void setOptions(const SessionToken &st, uint32_t options) = 0; -- Gitee From 3d3026da3ba5c16d57f5dd7d7a85369a34ab8661 Mon Sep 17 00:00:00 2001 From: Hevake Date: Sun, 6 Mar 2022 21:28:06 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E8=A7=A3=E5=86=B3TcpServer::disconnect()?= =?UTF-8?q?=E4=B9=8B=E5=90=8E=E6=B2=A1=E6=9C=89=E9=87=8A=E6=94=BE=E5=AF=B9?= =?UTF-8?q?=E8=B1=A1=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- network/tcp_server.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/network/tcp_server.cpp b/network/tcp_server.cpp index 5a419f3..aec6a85 100644 --- a/network/tcp_server.cpp +++ b/network/tcp_server.cpp @@ -137,9 +137,12 @@ bool TcpServer::send(const ClientToken &client, const void *data_ptr, size_t dat bool TcpServer::disconnect(const ClientToken &client) { - auto conn = d_->conns.at(client); - if (conn != nullptr) - return conn->disconnect(); + auto conn = d_->conns.remove(client); + if (conn != nullptr) { + conn->disconnect(); + d_->wp_loop->run([conn] { delete conn; }); + return true; + } return false; } -- Gitee