2020年注定会被历史铭记,世界遭受着一场前所未有的灾难,这种灾难到现在还在持续。还记得19年末的时候,那时候听到一点点消息,哪里想得到年关难过,灾难来的让人猝不及防。由于疫情防控,2020年感觉转瞬即逝,仿佛晃眼的功夫。本来做些自身职业上的改变,去年因为自身的原因因此搁浅。想想这几年自己维护的这个框架并未有太大的起色,甚者一度遗忘了它,所规划的很多内容并未得到实现。自己的懒惰搁浅,未免是对生命的严重浪费。今年的虽然暂时没有太多的计划,但是改变已经走在路上,希望这对自己的人生有所帮助。plain framework原本是面向游戏服务器设计的,不过在设计上尽量兼容所有的网络应用,从14年开始到现在已经六七年了,经过多次的修改,也扩充了不少的接口,在使用上更加的便捷。在这篇总结中,我主要讲述的是最近加入的控制台(console)模块,其实这个模块在许多框架中是很常见的。未来的技术日新月异,如果大家对编程上面有所兴趣,不妨可以做一定的参考,如有不足的地方也请指正,我将认真的思考其中遗留的问题。在这里我也祝愿大家在2021年,在风雨之后迎来希望的彩虹!

总结

  在以前的文章中,我已经总结过plain framework的成长过程,从C++98到C++11经历了不小的变化。如今的目录结构和当初很不同,从参考到自己的一些设计,让整个框架越来越好用越来越高效是最终的目的。但是这种改变是漫长的,而且总觉得力不从心,许多的设计虽然有过临时的想法始终没能得到执行。当前这个框架现阶段如果直接用于项目中问题不大,却不能保证有所隐藏的一些BUG。今年我要做出一些改变,不单单做游戏方面的设计,我对于未来的技术也有过兴趣,如在之前的项目中使用过VUE框架来做后台的相应设计。不过相对于未来,算法始终是大方向以及技术上需要突破的,比如AI人工智能,其中的算法需要许多的数学知识,但这些相应的知识我自己要么遗忘要么还没认真接触,作为自己的兴趣后续会向这些方向研究。

  人生总要有些改变,支持迟来和早来!因此我需要有段时间来放空脑袋,想一想未来的方向了。随着年龄的增长就产生了一种莫名的危机感,在职业上也有些乏味缺少新鲜,但是生活总是要继续的。一个人如果有了计划而不执行,到了没有精力和时间去做得时候,那时候再后悔未免可笑。因此我觉得一个人就得坚定地向着自己的目标走去,就算目标看来那样遥不可及,但我们可以不断改变策略,毕竟没有人随随便便就成功,但如果不去行动那么连成功的机会都没有。

  希望大家都能慢慢接近自己的理想,也希望这场人类的灾难早点过去!

控制台(console)

  控制台是在应用中提供调试的工具,一般情况下可以来分析应用运行过程中一些数据。在经典的操作系统中,控制台实在是太常见了,如windows中的命令行控制器,可以使用相应的命令对系统或者应用进行运行、调试和分析。

  

  plain framework加入控制台的目的,也是为了调试以及在应用运行中做一些调试和处理,提供了比较丰富的命令接口使得外部注册命令比较容易。在服务器的设计中,很多时候想要看看应用的线程内存情况,还有网络的链接和数据的收发情况。增加控制台,有助于我们在测试的时候,对不同情况下特别是压力测试时分析出重要的数据,这有助于帮助我们对程序进行优化。目前PF 中的命令不多,主要几个常见的命令,后续会继续完善。

  下图为PF中控制台的调试(包括在LINUX下的编译部分),目前仅支持网络调试(直接输入的方式很快集成,由于感觉用处不大暂时没实现):

部分代码

  由于控制台需要使用网络命令行,因此在框架中增加了standard的网络协议(protocol),这个网络协议是遇到换行便将内容读出并调用注册的执行接口:

  1. #include "pf/basic/string.h"
  2. #include "pf/net/stream/input.h"
  3. #include "pf/net/stream/output.h"
  4. #include "pf/net/connection/basic.h"
  5. #include "pf/net/connection/manager/listener.h"
  6. #include "pf/net/protocol/standard.h"
  7.  
  8. using namespace pf_basic::string;
  9. using namespace pf_net::protocol;
  10.  
  11. bool Standard::command(connection::Basic *connection, uint16_t count) {
  12. if (connection->is_disconnect()) return false; //Leave this when not connected.
  13. stream::Input *istream = &connection->istream();
  14. auto line = istream->readline();
  15. if (!line.empty()) {
  16. if (!connection->check_safe_encrypt()) return false;
  17. auto listener = connection->get_listener();
  18. if (!is_null(listener)) {
  19. rtrim(line); // Remove '\n' '\r' or other words on last.
  20. auto callback = listener->get_standard_callback();
  21. if (callback) callback(line, connection);
  22. }
  23. }
  24. return true;
  25. }
  26.  
  27. bool Standard::send(connection::Basic *connection, packet::Interface *packet) {
  28. return true;
  29. }

  在处理命令的时候注册的回调函数如下:

  1. void console_net_handle(
  2. const std::string &cmd, pf_net::connection::Basic *connection) {
  3. using namespace pf_console;
  4. using namespace pf_basic::string;
  5. if (is_null(ENGINE_POINTER)) return;
  6. auto console = ENGINE_POINTER->get_console();
  7. if (is_null(console)) return;
  8. if ("quit" == cmd) {
  9. connection->exit();
  10. return;
  11. }
  12. StringInput input(cmd);
  13. NetOutput output(connection);
  14. console->run(&input, &output);
  15. }

  整个控制台的实现目录结构如下:

  控制台应用代码:

  1. #include "pf/basic/string.h"
  2. #include "pf/console/argv_input.h"
  3. #include "pf/console/array_input.h"
  4. #include "pf/console/commands/app.h"
  5. #include "pf/console/commands/help.h"
  6. #include "pf/console/commands/list.h"
  7. #include "pf/basic/logger.h"
  8. #include "pf/console/application.h"
  9.  
  10. using namespace pf_console;
  11. using namespace pf_interfaces::console;
  12. using namespace pf_basic::string;
  13.  
  14. uint8_t Application::run(Input *input, Output *output) {
  15. std::unique_ptr<Input> input_temp;
  16. std::unique_ptr<Output> output_temp;
  17. if (is_null(input)) {
  18. unique_move(Input, new ArgvInput(), input_temp);
  19. input = input_temp.get();
  20. }
  21. if (is_null(output)) {
  22. unique_move(Output, new Output(), output_temp);
  23. output = output_temp.get();
  24. }
  25. configure_IO(input, output);
  26. uint8_t exit_code{0};
  27. try {
  28. exit_code = do_run(input, output);
  29. } catch (std::exception &e) {
  30. std::cout << "Application::run get error!!!: " << e.what() << std::endl;
  31. }
  32. return exit_code;
  33. }
  34.  
  35. uint8_t Application::do_run(Input *input, Output *output) {
  36. if (input->has_parameter_option({"--version", "-V"})) {
  37. output->write_ln(get_long_version());
  38. return 0;
  39. }
  40. try {
  41. input->bind(get_definition());
  42. } catch(...) {
  43.  
  44. }
  45. auto name = get_command_name(input);
  46. std::unique_ptr<Input> input_temp;
  47. if (input->has_parameter_option({"--help", "-h"}, true)) {
  48. if (name == "") {
  49. name = "help";
  50. unique_move(Input,
  51. new ArrayInput({{"command_name", default_command_name_}}),
  52. input_temp);
  53. input = input_temp.get();
  54. } else {
  55. want_helps_ = false;
  56. }
  57. }
  58. if (name == "") {
  59. name = default_command_name_;
  60. auto definition = get_definition();
  61. definition->set_argument(InputArgument("command",
  62. InputArgument::kModeOptional,
  63. definition->get_argument("command").get_description(), name));
  64. }
  65. Command *command{nullptr};
  66. try {
  67. running_command_ = nullptr;
  68. command = find(name);
  69. } catch (...) {
  70.  
  71. }
  72. if (is_null(command)) {
  73. FAST_ERRORLOG(CONSOLE_MODULENAME,
  74. "[console] (Application::run)"
  75. " can't find the command: %s",
  76. name.c_str());
  77. return 1;
  78. }
  79. running_command_ = command;
  80. auto exit_code = do_runcommand(command, input, output);
  81. return exit_code;
  82. }
  83.  
  84. InputDefinition *Application::get_definition() {
  85. if (is_null(definition_)) {
  86. std::unique_ptr<InputDefinition> temp(new InputDefinition());
  87. *temp = get_default_input_definition();
  88. definition_ = std::move(temp);
  89. if (single_command_) {
  90. if (is_null(definition_temp_)) {
  91. unique_move(InputDefinition, new InputDefinition(), definition_temp_);
  92. *definition_temp_ = *definition_;
  93. }
  94. definition_temp_->set_arguments({});
  95. return definition_temp_.get();
  96. }
  97. }
  98. return definition_.get();
  99. }
  100.  
  101. std::string Application::get_long_version() const {
  102. std::string r{"Console Tool"};
  103. if (name_ != "") {
  104. if (version_ != "") {
  105. r = name_ + " " + version_;
  106. }
  107. r = name_;
  108. }
  109. return r;
  110. }
  111.  
  112. Command *Application::add(Command *command) {
  113. // std::cout << "Add command: " << command->name() << std::endl;
  114. if (!command->is_enabled()) {
  115. return nullptr;
  116. }
  117. init();
  118. command->set_application(this);
  119. // Will throw if the command is not correctly initialized.
  120. command->get_definition();
  121. command->configure();
  122. auto name = command->name();
  123. if (name == "") {
  124. throw std::logic_error("command cannot have an empty name.");
  125. }
  126. if (commands_.find(name) != commands_.end()) {
  127. return commands_[name].get();
  128. }
  129. std::unique_ptr<Command> temp;
  130. unique_move(Command, command, temp);
  131. commands_[name] = std::move(temp);
  132. for (auto const &alias : command->get_aliases()) {
  133. command_aliases_[alias] = name;
  134. }
  135. return command;
  136. }
  137.  
  138. Command *Application::get(const std::string &_name) {
  139. auto name = get_command_real_name(_name);
  140. if ("" == name) {
  141. std::string e = "The command \"" + _name + "\" does not exist.";
  142. throw std::invalid_argument(e);
  143. }
  144. if (commands_.find(name) == commands_.end()) return nullptr;
  145. auto command = commands_[name].get();
  146. if (want_helps_) {
  147. want_helps_ = false;
  148. auto help_command = get("help");
  149. help_command->set_command(command);
  150. return help_command;
  151. }
  152. return command;
  153. }
  154.  
  155. std::vector<std::string> Application::get_namespaces() {
  156. std::vector<std::string> r;
  157. auto commands = all();
  158. for (auto it = commands.begin(); it != commands.end(); ++it) {
  159. if (it->second->is_hidden()) continue;
  160. auto temp = extract_all_namespace(it->first);
  161. for (const auto &one : temp) r.emplace_back(one);
  162. for (const auto &alias : it->second->get_aliases()) {
  163. auto temp1 = extract_all_namespace(alias);
  164. for (const auto &one : temp1) r.emplace_back(one);
  165. }
  166. }
  167. // * The result maybe need use array_unique to remove the same values.
  168. return r;
  169. }
  170.  
  171. std::string Application::find_namespace(const std::string &_namespace) {
  172. return "";
  173. }
  174.  
  175. Command *Application::find(const std::string &name) {
  176. init();
  177. for (auto it = commands_.begin(); it != commands_.end(); ++it) {
  178. if (!is_null(it->second)) {
  179. for (const auto &alias : it->second->get_aliases()) {
  180. if ("" == command_aliases_[alias])
  181. command_aliases_[alias] = it->second->name();
  182. }
  183. } else {
  184. std::cout << "find no command: " << it->first << std::endl;
  185. }
  186. }
  187. return get(name);
  188. }
  189.  
  190. std::map<std::string, Command *>
  191. Application::all(const std::string &_namespace) {
  192. std::map<std::string, Command *> r;
  193. init();
  194. if ("" == _namespace) {
  195. for (auto it = commands_.begin(); it != commands_.end(); ++it) {
  196. r[it->first] = it->second.get();
  197. }
  198. return r;
  199. }
  200. for (auto it = commands_.begin(); it != commands_.end(); ++it) {
  201. if (_namespace == extract_namespace(it->first)) {
  202. r[it->first] = it->second.get();
  203. }
  204. }
  205. return r;
  206. }
  207.  
  208. Application &Application::set_default_command(
  209. const std::string &name, bool is_single_command) {
  210. default_command_name_ = name;
  211. if (is_single_command) {
  212. // Ensure the command exist
  213. find(name);
  214. single_command_ = true;
  215. }
  216. return *this;
  217. }
  218.  
  219. uint8_t Application::do_runcommand(
  220. Command *command, Input *input, Output *output) {
  221. // std::cout << "do_runcommand: " << command->name() << std::endl;
  222. return command->run(input, output);
  223. }
  224.  
  225. std::string Application::get_command_name(Input *input) const {
  226. return single_command_ ? default_command_name_ : input->get_first_argument();
  227. }
  228.  
  229. InputDefinition Application::get_default_input_definition() const {
  230. std::vector<InputParameter *> p;
  231. std::unique_ptr<InputParameter> p1(new InputArgument(
  232. "command", InputParameter::kModeRequired,
  233. "The command to execute", ""
  234. ));
  235. p.emplace_back(p1.get());
  236. std::unique_ptr<InputParameter> p2(new InputOption(
  237. "--help", "-h", InputParameter::kModeNone,
  238. "Display help for the given command. When no command"
  239. " is given display help for the" + default_command_name_ + "command", ""
  240. ));
  241. p.emplace_back(p2.get());
  242. std::unique_ptr<InputParameter> p3(new InputOption(
  243. "--quiet", "-q", InputParameter::kModeNone,
  244. "Do not output any message", ""
  245. ));
  246. p.emplace_back(p3.get());
  247. std::unique_ptr<InputParameter> p4(new InputOption(
  248. "--verbose", "-v|vv|vvv", InputParameter::kModeNone,
  249. "Increase the verbosity of messages: 1 for normal output, "
  250. "2 for more verbose output and 3 for debug", ""
  251. ));
  252. p.emplace_back(p4.get());
  253. std::unique_ptr<InputParameter> p5(new InputOption(
  254. "--version", "-V", InputParameter::kModeNone,
  255. "Display this application version", ""
  256. ));
  257. p.emplace_back(p5.get());
  258. std::unique_ptr<InputParameter> p6(new InputOption(
  259. "--ansi", "", InputParameter::kModeNone,
  260. "Force ANSI output", ""
  261. ));
  262. p.emplace_back(p6.get());
  263. std::unique_ptr<InputParameter> p7(new InputOption(
  264. "--no-ansi", "", InputParameter::kModeNone,
  265. "Disable ANSI output", ""
  266. ));
  267. p.emplace_back(p7.get());
  268. std::unique_ptr<InputParameter> p8(new InputOption(
  269. "--no-interaction", "-n", InputParameter::kModeNone,
  270. "Do not ask any interactive question", ""
  271. ));
  272. p.emplace_back(p8.get());
  273.  
  274. return InputDefinition(p);
  275. }
  276.  
  277. std::vector<Command *> Application::get_default_commands() const {
  278. std::vector<Command *> r;
  279. return r;
  280. }
  281.  
  282. std::string Application::get_abbreviation_suggestions(
  283. const std::vector<std::string> &abbrevs) const {
  284. return "";
  285. }
  286.  
  287. std::vector<std::string> Application::find_alternatives(
  288. const std::string &name, const std::vector<std::string> &collection) const {
  289. return {};
  290. }
  291.  
  292. void Application::configure_IO(Input *input, Output *output) {
  293. if (input->has_parameter_option({"--ansi"}, true)) {
  294. output->set_decorated(true);
  295. } else if (input->has_parameter_option({"'--no-ansi'"}, true)) {
  296. output->set_decorated(false);
  297. }
  298. }
  299.  
  300. std::vector<std::string> Application::extract_all_namespace(
  301. const std::string &name) {
  302. std::vector<std::string> r;
  303. std::vector<std::string> parts;
  304. explode(name.c_str(), parts, ":", true, true);
  305. for (const auto &part : parts) {
  306. if (r.size() > 0) {
  307. std::string temp = r[r.size() - 1] + ":" + part;
  308. r.emplace_back(temp);
  309. } else {
  310. r.emplace_back(part);
  311. }
  312. }
  313. return r;
  314. }
  315.  
  316. std::string Application::extract_namespace(
  317. const std::string &name, int32_t limit) const {
  318. return "";
  319. }
  320.  
  321. void Application::init() {
  322. if (initialized_) return;
  323. initialized_ = true;
  324. // std::cout << "Application::init" << std::endl;
  325. add(new commands::Help());
  326. add(new commands::List());
  327. add(new commands::App());
  328. }

  命令实现代码:

  1. #include "pf/basic/string.h"
  2. #include "pf/console/argv_input.h"
  3. #include "pf/console/array_input.h"
  4. #include "pf/console/commands/app.h"
  5. #include "pf/console/commands/help.h"
  6. #include "pf/console/commands/list.h"
  7. #include "pf/basic/logger.h"
  8. #include "pf/console/application.h"
  9.  
  10. using namespace pf_console;
  11. using namespace pf_interfaces::console;
  12. using namespace pf_basic::string;
  13.  
  14. uint8_t Application::run(Input *input, Output *output) {
  15. std::unique_ptr<Input> input_temp;
  16. std::unique_ptr<Output> output_temp;
  17. if (is_null(input)) {
  18. unique_move(Input, new ArgvInput(), input_temp);
  19. input = input_temp.get();
  20. }
  21. if (is_null(output)) {
  22. unique_move(Output, new Output(), output_temp);
  23. output = output_temp.get();
  24. }
  25. configure_IO(input, output);
  26. uint8_t exit_code{0};
  27. try {
  28. exit_code = do_run(input, output);
  29. } catch (std::exception &e) {
  30. std::cout << "Application::run get error!!!: " << e.what() << std::endl;
  31. }
  32. return exit_code;
  33. }
  34.  
  35. uint8_t Application::do_run(Input *input, Output *output) {
  36. if (input->has_parameter_option({"--version", "-V"})) {
  37. output->write_ln(get_long_version());
  38. return 0;
  39. }
  40. try {
  41. input->bind(get_definition());
  42. } catch(...) {
  43.  
  44. }
  45. auto name = get_command_name(input);
  46. std::unique_ptr<Input> input_temp;
  47. if (input->has_parameter_option({"--help", "-h"}, true)) {
  48. if (name == "") {
  49. name = "help";
  50. unique_move(Input,
  51. new ArrayInput({{"command_name", default_command_name_}}),
  52. input_temp);
  53. input = input_temp.get();
  54. } else {
  55. want_helps_ = false;
  56. }
  57. }
  58. if (name == "") {
  59. name = default_command_name_;
  60. auto definition = get_definition();
  61. definition->set_argument(InputArgument("command",
  62. InputArgument::kModeOptional,
  63. definition->get_argument("command").get_description(), name));
  64. }
  65. Command *command{nullptr};
  66. try {
  67. running_command_ = nullptr;
  68. command = find(name);
  69. } catch (...) {
  70.  
  71. }
  72. if (is_null(command)) {
  73. FAST_ERRORLOG(CONSOLE_MODULENAME,
  74. "[console] (Application::run)"
  75. " can't find the command: %s",
  76. name.c_str());
  77. return 1;
  78. }
  79. running_command_ = command;
  80. auto exit_code = do_runcommand(command, input, output);
  81. return exit_code;
  82. }
  83.  
  84. InputDefinition *Application::get_definition() {
  85. if (is_null(definition_)) {
  86. std::unique_ptr<InputDefinition> temp(new InputDefinition());
  87. *temp = get_default_input_definition();
  88. definition_ = std::move(temp);
  89. if (single_command_) {
  90. if (is_null(definition_temp_)) {
  91. unique_move(InputDefinition, new InputDefinition(), definition_temp_);
  92. *definition_temp_ = *definition_;
  93. }
  94. definition_temp_->set_arguments({});
  95. return definition_temp_.get();
  96. }
  97. }
  98. return definition_.get();
  99. }
  100.  
  101. std::string Application::get_long_version() const {
  102. std::string r{"Console Tool"};
  103. if (name_ != "") {
  104. if (version_ != "") {
  105. r = name_ + " " + version_;
  106. }
  107. r = name_;
  108. }
  109. return r;
  110. }
  111.  
  112. Command *Application::add(Command *command) {
  113. // std::cout << "Add command: " << command->name() << std::endl;
  114. if (!command->is_enabled()) {
  115. return nullptr;
  116. }
  117. init();
  118. command->set_application(this);
  119. // Will throw if the command is not correctly initialized.
  120. command->get_definition();
  121. command->configure();
  122. auto name = command->name();
  123. if (name == "") {
  124. throw std::logic_error("command cannot have an empty name.");
  125. }
  126. if (commands_.find(name) != commands_.end()) {
  127. return commands_[name].get();
  128. }
  129. std::unique_ptr<Command> temp;
  130. unique_move(Command, command, temp);
  131. commands_[name] = std::move(temp);
  132. for (auto const &alias : command->get_aliases()) {
  133. command_aliases_[alias] = name;
  134. }
  135. return command;
  136. }
  137.  
  138. Command *Application::get(const std::string &_name) {
  139. auto name = get_command_real_name(_name);
  140. if ("" == name) {
  141. std::string e = "The command \"" + _name + "\" does not exist.";
  142. throw std::invalid_argument(e);
  143. }
  144. if (commands_.find(name) == commands_.end()) return nullptr;
  145. auto command = commands_[name].get();
  146. if (want_helps_) {
  147. want_helps_ = false;
  148. auto help_command = get("help");
  149. help_command->set_command(command);
  150. return help_command;
  151. }
  152. return command;
  153. }
  154.  
  155. std::vector<std::string> Application::get_namespaces() {
  156. std::vector<std::string> r;
  157. auto commands = all();
  158. for (auto it = commands.begin(); it != commands.end(); ++it) {
  159. if (it->second->is_hidden()) continue;
  160. auto temp = extract_all_namespace(it->first);
  161. for (const auto &one : temp) r.emplace_back(one);
  162. for (const auto &alias : it->second->get_aliases()) {
  163. auto temp1 = extract_all_namespace(alias);
  164. for (const auto &one : temp1) r.emplace_back(one);
  165. }
  166. }
  167. // * The result maybe need use array_unique to remove the same values.
  168. return r;
  169. }
  170.  
  171. std::string Application::find_namespace(const std::string &_namespace) {
  172. return "";
  173. }
  174.  
  175. Command *Application::find(const std::string &name) {
  176. init();
  177. for (auto it = commands_.begin(); it != commands_.end(); ++it) {
  178. if (!is_null(it->second)) {
  179. for (const auto &alias : it->second->get_aliases()) {
  180. if ("" == command_aliases_[alias])
  181. command_aliases_[alias] = it->second->name();
  182. }
  183. } else {
  184. std::cout << "find no command: " << it->first << std::endl;
  185. }
  186. }
  187. return get(name);
  188. }
  189.  
  190. std::map<std::string, Command *>
  191. Application::all(const std::string &_namespace) {
  192. std::map<std::string, Command *> r;
  193. init();
  194. if ("" == _namespace) {
  195. for (auto it = commands_.begin(); it != commands_.end(); ++it) {
  196. r[it->first] = it->second.get();
  197. }
  198. return r;
  199. }
  200. for (auto it = commands_.begin(); it != commands_.end(); ++it) {
  201. if (_namespace == extract_namespace(it->first)) {
  202. r[it->first] = it->second.get();
  203. }
  204. }
  205. return r;
  206. }
  207.  
  208. Application &Application::set_default_command(
  209. const std::string &name, bool is_single_command) {
  210. default_command_name_ = name;
  211. if (is_single_command) {
  212. // Ensure the command exist
  213. find(name);
  214. single_command_ = true;
  215. }
  216. return *this;
  217. }
  218.  
  219. uint8_t Application::do_runcommand(
  220. Command *command, Input *input, Output *output) {
  221. // std::cout << "do_runcommand: " << command->name() << std::endl;
  222. return command->run(input, output);
  223. }
  224.  
  225. std::string Application::get_command_name(Input *input) const {
  226. return single_command_ ? default_command_name_ : input->get_first_argument();
  227. }
  228.  
  229. InputDefinition Application::get_default_input_definition() const {
  230. std::vector<InputParameter *> p;
  231. std::unique_ptr<InputParameter> p1(new InputArgument(
  232. "command", InputParameter::kModeRequired,
  233. "The command to execute", ""
  234. ));
  235. p.emplace_back(p1.get());
  236. std::unique_ptr<InputParameter> p2(new InputOption(
  237. "--help", "-h", InputParameter::kModeNone,
  238. "Display help for the given command. When no command"
  239. " is given display help for the" + default_command_name_ + "command", ""
  240. ));
  241. p.emplace_back(p2.get());
  242. std::unique_ptr<InputParameter> p3(new InputOption(
  243. "--quiet", "-q", InputParameter::kModeNone,
  244. "Do not output any message", ""
  245. ));
  246. p.emplace_back(p3.get());
  247. std::unique_ptr<InputParameter> p4(new InputOption(
  248. "--verbose", "-v|vv|vvv", InputParameter::kModeNone,
  249. "Increase the verbosity of messages: 1 for normal output, "
  250. "2 for more verbose output and 3 for debug", ""
  251. ));
  252. p.emplace_back(p4.get());
  253. std::unique_ptr<InputParameter> p5(new InputOption(
  254. "--version", "-V", InputParameter::kModeNone,
  255. "Display this application version", ""
  256. ));
  257. p.emplace_back(p5.get());
  258. std::unique_ptr<InputParameter> p6(new InputOption(
  259. "--ansi", "", InputParameter::kModeNone,
  260. "Force ANSI output", ""
  261. ));
  262. p.emplace_back(p6.get());
  263. std::unique_ptr<InputParameter> p7(new InputOption(
  264. "--no-ansi", "", InputParameter::kModeNone,
  265. "Disable ANSI output", ""
  266. ));
  267. p.emplace_back(p7.get());
  268. std::unique_ptr<InputParameter> p8(new InputOption(
  269. "--no-interaction", "-n", InputParameter::kModeNone,
  270. "Do not ask any interactive question", ""
  271. ));
  272. p.emplace_back(p8.get());
  273.  
  274. return InputDefinition(p);
  275. }
  276.  
  277. std::vector<Command *> Application::get_default_commands() const {
  278. std::vector<Command *> r;
  279. return r;
  280. }
  281.  
  282. std::string Application::get_abbreviation_suggestions(
  283. const std::vector<std::string> &abbrevs) const {
  284. return "";
  285. }
  286.  
  287. std::vector<std::string> Application::find_alternatives(
  288. const std::string &name, const std::vector<std::string> &collection) const {
  289. return {};
  290. }
  291.  
  292. void Application::configure_IO(Input *input, Output *output) {
  293. if (input->has_parameter_option({"--ansi"}, true)) {
  294. output->set_decorated(true);
  295. } else if (input->has_parameter_option({"'--no-ansi'"}, true)) {
  296. output->set_decorated(false);
  297. }
  298. }
  299.  
  300. std::vector<std::string> Application::extract_all_namespace(
  301. const std::string &name) {
  302. std::vector<std::string> r;
  303. std::vector<std::string> parts;
  304. explode(name.c_str(), parts, ":", true, true);
  305. for (const auto &part : parts) {
  306. if (r.size() > 0) {
  307. std::string temp = r[r.size() - 1] + ":" + part;
  308. r.emplace_back(temp);
  309. } else {
  310. r.emplace_back(part);
  311. }
  312. }
  313. return r;
  314. }
  315.  
  316. std::string Application::extract_namespace(
  317. const std::string &name, int32_t limit) const {
  318. return "";
  319. }
  320.  
  321. void Application::init() {
  322. if (initialized_) return;
  323. initialized_ = true;
  324. // std::cout << "Application::init" << std::endl;
  325. add(new commands::Help());
  326. add(new commands::List());
  327. add(new commands::App());
  328. }
  329. [viticm@izuf633l0ge76tbdctmljaz core]$ cat /home/viticm/develop/github/plain/framework/core/src/console/command.cc
  330. #include "pf/support/helpers.h"
  331. #include "pf/console/application.h"
  332. #include "pf/console/command.h"
  333.  
  334. using namespace pf_support;
  335. using namespace pf_console;
  336.  
  337. // Static member must be initialized.
  338. std::string Command::default_name_{"unknown"};
  339.  
  340. void Command::merge_application_definition(bool merge_args) {
  341. if (is_null(app_) or !is_null(full_definition_)) return;
  342. unique_move(InputDefinition, new InputDefinition(), full_definition_);
  343. full_definition_->set_options(array_values(definition_->get_options()));
  344. full_definition_->add_options(
  345. array_values(app_->get_definition()->get_options()));
  346. if (merge_args) {
  347. full_definition_->set_arguments(
  348. array_values(app_->get_definition()->get_arguments()));
  349. full_definition_->add_arguments(array_values(definition_->get_arguments()));
  350. } else {
  351. full_definition_->set_arguments(array_values(definition_->get_arguments()));
  352. }
  353. }
  354.  
  355. uint8_t Command::run(Input *input, Output *output) {
  356. uint8_t r{0};
  357. merge_application_definition();
  358. // bind the input against the command specific arguments/options
  359. try {
  360. input->bind(get_definition(), is_parse_input());
  361. } catch (std::exception &e) {
  362. if (!ignore_validation_errors_)
  363. throw std::runtime_error(e.what());
  364. }
  365. initialize(input, output);
  366.  
  367. // Set process title.
  368. if (!process_title_.empty()) {
  369.  
  370. }
  371. if (input->is_interactive()) {
  372. interact(input, output);
  373. }
  374.  
  375. // The command name argument is often omitted when a command is executed
  376. // directly with its run() method.
  377. // It would fail the validation if we didn't make sure the command argument
  378. // is present, since it's required by the application.
  379. if (input->has_argument("command") && input->get_argument("command") == "") {
  380. input->set_argument("command", name_);
  381. }
  382.  
  383. input->validate();
  384.  
  385. if (code_) {
  386. r = code_(input, output);
  387. } else {
  388. r = execute(input, output);
  389. }
  390.  
  391. return r;
  392. }

更多

  可以在github上找到完整的项目:https://github.com/viticm/plain

开源服务器设计总计(plain framework2020年总计)的更多相关文章

  1. 转:Nginx+ffmpeg的HLS开源服务器搭建配置及开发详解

    转:http://itindex.net/detail/51186-nginx-ffmpeg-hls 本文概述: 至目前为止,HLS 是移动平台上非常重要并十分流行的流媒体传输协议.做移动平台的流媒体 ...

  2. DNS开源服务器BIND最小配置详解<转>

    一,简介 相对于存储和大数据领域,CDN是一个相对小的领域,但行行出状元,BIND就是CDN领域的蝉联N届的状元郎.BIND是一款非常常用的DNS开源服务器,全球有90%的DNS用BIND实现.值得一 ...

  3. DNS开源服务器BIND最小配置详解

    一,简介 相对于存储和大数据领域,CDN是一个相对小的领域,但行行出状元,BIND就是CDN领域的蝉联N届的状元郎.BIND是一款非常常用的DNS开源服务器,全球有90%的DNS用BIND实现.值得一 ...

  4. Nginx+ffmpeg的HLS开源服务器搭建配置及开发详

    本文概述: 至目前为止,HLS 是移动平台上非常重要并十分流行的流媒体传输协议.做移动平台的流媒体开发,不知道它不掌握它 ,真是一大遗憾.而HLS的平台搭建有一定的难度,本文针对对该方向有一定了解的朋 ...

  5. 基于内存,redis,mysql的高速游戏数据服务器设计架构

    转载请注明出处,欢迎大家批评指正 1.数据服务器详细设计 数据服务器在设计上采用三个层次的数据同步,实现玩家数据的高速获取和修改. 数据层次上分为:内存数据,redis数据,mysql数据 设计目的: ...

  6. H2Engine游戏服务器设计之属性管理器

    游戏服务器设计之属性管理器 游戏中角色拥有的属性值很多,运营多年的游戏,往往会有很多个成长线,每个属性都有可能被N个成长线模块增减数值.举例当角色戴上武器时候hp+100点,卸下武器时HP-100点, ...

  7. 游戏服务器设计之NPC系统

    游戏服务器设计之NPC系统 简介 NPC系统是游戏中非常重要的系统,设计的好坏很大程度上影响游戏的体验.NPC在游戏中有如下作用: 引导玩家体验游戏内容,一般游戏内有很多主线.支线任务,而任务的介绍. ...

  8. h2engine游戏服务器设计之聊天室示例

    游戏服务器设计之聊天室示例 简介 h2engine引擎建群以后,有热心网友向我反馈,想尝试h2engine但是没有服务器开发经验觉得无从入手,希望我能提供一个简单明了的示例.由于前一段时间工作实在忙碌 ...

  9. 基于内存,redis,mysql的高速游戏数据服务器设计架构 ZT

    zt  http://www.cnblogs.com/captainl1993/p/4788236.html 1.数据服务器详细设计 数据服务器在设计上采用三个层次的数据同步,实现玩家数据的高速获取和 ...

随机推荐

  1. TYLER ADAMS BRADBERRY:人到中年,要学会戒掉这三点

    在一些国家的一些人当中,总会出现这样一个问题"中年危机".而到了中年,人与人间的差距似乎也变得越来越大.有人说,人到中年,是一个门槛,有的人迈过去了,有的人没迈过去.但是,其实实话 ...

  2. mysql一张表到底能存多少数据?

    前言 程序员平时和mysql打交道一定不少,可以说每天都有接触到,但是mysql一张表到底能存多少数据呢?计算根据是什么呢?接下来咱们逐一探讨 知识准备 数据页 在操作系统中,我们知道为了跟磁盘交互, ...

  3. WPF MVVM实例三

    在没给大家讲解wpf mwm示例之前先给大家简单说下MVVM理论知识: WPF技术的主要特点是数据驱动UI,所以在使用WPF技术开发的过程中是以数据为核心的,WPF提供了数据绑定机制,当数据发生变化时 ...

  4. idea 如何在新窗口中打开项目

    参考链接:https://blog.csdn.net/dreamfly88/article/details/52240188 以前一直再用eclipse,可以同时打开好几个项目,idea中同样支持打开 ...

  5. Django练习遇到的错误记录

    _reverse_with_prefix() argument after ** must be a mapping, not set 错误代码: def get_absolute_url(self) ...

  6. Pyqt5——表格中隐藏的控件(Model/View/Delegate)

    需求:在TableView表格中点击单元格可以实现编辑功能.性别由LineEdite控件编辑,年龄由spinBox控件编辑. 实现:(1)使用Qt的model-view模式生成表格视图.    (2) ...

  7. PUToast - 使用PopupWindow在Presentation上模拟Toast

    PUToast Android10 (API 29) 之前 Toast 组件默认只能展示在主 Display 上,PUToast 通过构造一个 PopupWindoww 在 Presentation ...

  8. mysql 使用sleep操作 update 来停止一段时间执行语句 [骚操作]

    update mytestTable inner join(select '2' as id, sleep(5)) a on mytestTable.id=a.id set mytestTable.n ...

  9. 一篇看懂JVM底层详解,利用class反编译文件了解文件执行流程

    JVM之内存结构详解 JVM内存结构 java虚拟机在执行程序的过程中会将内存划分为不同的区域,具体如图1-1所示. 五个区域 JVM分为五个区域:堆.虚拟机栈.本地方法栈.方法区(元空间).程序计数 ...

  10. ajax轮询原理及其实现方式

    ajax轮询原理及其实现方式 ajax轮询的两种方式 方式1:设定一个定时器,无论有无结果返回,时间一到就会继续发起请求,这种轮询耗费资源,也不一定能得到想要的数据,这样的轮询是不推荐的. 方式2: ...