srpc_basic_controller.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. /*
  2. Copyright (c) 2022 Sogou, Inc.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string>
  16. #include <string.h>
  17. #include <sys/stat.h>
  18. #include <sys/types.h>
  19. #include <dirent.h>
  20. #include <fcntl.h>
  21. #include <unordered_map>
  22. #include "srpc_controller.h"
  23. using DEFAULT_FILES = std::vector<struct CommandController::file_info>;
  24. static std::string server_process_codes(uint8_t type)
  25. {
  26. if (type == PROTOCOL_TYPE_HTTP)
  27. return std::string(R"(
  28. fprintf(stderr, "http server get request_uri: %s\n",
  29. task->get_req()->get_request_uri());
  30. print_peer_address(task);
  31. task->get_resp()->append_output_body("<html>Hello from server!</html>");)");
  32. if (type == PROTOCOL_TYPE_REDIS)
  33. return std::string(R"(
  34. protocol::RedisRequest *req = task->get_req();
  35. protocol::RedisResponse *resp = task->get_resp();
  36. protocol::RedisValue val;
  37. std::string cmd;
  38. if (req->parse_success() == false || req->get_command(cmd) == false)
  39. return;
  40. fprintf(stderr, "redis server get cmd: [%s] from ", cmd.c_str());
  41. print_peer_address(task);
  42. val.set_status("OK"); // example: return OK to every requests
  43. resp->set_result(val);)");
  44. return std::string("Unknown type");
  45. }
  46. static std::string client_redirect_codes(uint8_t type)
  47. {
  48. if (type == PROTOCOL_TYPE_HTTP)
  49. return std::string(R"(
  50. config.redirect_max(),)");
  51. return std::string("");
  52. }
  53. static std::string client_task_callback_codes(uint8_t type)
  54. {
  55. if (type == PROTOCOL_TYPE_HTTP)
  56. return std::string(R"(
  57. if (state == WFT_STATE_SUCCESS) // print server response body
  58. {
  59. const void *body;
  60. size_t body_len;
  61. task->get_resp()->get_parsed_body(&body, &body_len);
  62. fwrite(body, 1, body_len, stdout);
  63. fflush(stdout);
  64. })");
  65. if (type == PROTOCOL_TYPE_REDIS)
  66. return std::string(R"(
  67. protocol::RedisResponse *resp = task->get_resp();
  68. protocol::RedisValue val;
  69. if (state == WFT_STATE_SUCCESS && resp->parse_success() == true)
  70. {
  71. resp->get_result(val);
  72. fprintf(stderr, "response: %s\n", val.string_value().c_str());
  73. })");
  74. return std::string("Unknown type");
  75. }
  76. static std::string client_set_request_codes(uint8_t type)
  77. {
  78. if (type == PROTOCOL_TYPE_HTTP)
  79. return std::string(R"(
  80. protocol::HttpRequest *req = task->get_req();
  81. req->set_request_uri("/client_request"); // will send to server by proxy
  82. )");
  83. if (type == PROTOCOL_TYPE_REDIS)
  84. return std::string(R"(
  85. task->get_req()->set_request("SET", {"k1", "v1"});
  86. )");
  87. return std::string("Unknown type");
  88. }
  89. static std::string username_passwd_codes(uint8_t type)
  90. {
  91. if (type == PROTOCOL_TYPE_REDIS || type == PROTOCOL_TYPE_MYSQL)
  92. return std::string(R"(config.client_user_name() +
  93. std::string(":") + config.client_password() +
  94. std::string("@") +)");
  95. return std::string("");
  96. }
  97. static uint8_t get_protocol_type(const struct srpc_config *config, uint8_t type)
  98. {
  99. if (config->type == COMMAND_HTTP || config->type == COMMAND_COMPUTE ||
  100. (config->type == COMMAND_PROXY && type == PROTOCOL_TYPE_HTTP))
  101. return PROTOCOL_TYPE_HTTP;
  102. if (config->type == COMMAND_REDIS ||
  103. (config->type == COMMAND_PROXY && type == PROTOCOL_TYPE_REDIS))
  104. return PROTOCOL_TYPE_REDIS;
  105. if (config->type == COMMAND_MYSQL ||
  106. (config->type == COMMAND_PROXY && type == PROTOCOL_TYPE_MYSQL))
  107. return PROTOCOL_TYPE_MYSQL;
  108. return PROTOCOL_TYPE_MAX;
  109. }
  110. static inline uint8_t get_client_protocol_type(const struct srpc_config *config)
  111. {
  112. return get_protocol_type(config, config->proxy_client_type);
  113. }
  114. static inline uint8_t get_server_protocol_type(const struct srpc_config *config)
  115. {
  116. return get_protocol_type(config, config->proxy_server_type);
  117. }
  118. bool basic_server_config_transform(const std::string& format, FILE *out,
  119. const struct srpc_config *config)
  120. {
  121. unsigned short port;
  122. if (get_server_protocol_type(config) == PROTOCOL_TYPE_HTTP)
  123. port = 8080;
  124. else if (get_server_protocol_type(config) == PROTOCOL_TYPE_REDIS)
  125. port = 6379;
  126. else if (get_server_protocol_type(config) == PROTOCOL_TYPE_MYSQL)
  127. port = 3306;
  128. else
  129. port = 1412;
  130. size_t len = fprintf(out, format.c_str(), port);
  131. return len > 0;
  132. }
  133. bool basic_client_config_transform(const std::string& format, FILE *out,
  134. const struct srpc_config *config)
  135. {
  136. unsigned short port;
  137. std::string redirect_code;
  138. std::string user_and_passwd;
  139. if (get_client_protocol_type(config) == PROTOCOL_TYPE_HTTP)
  140. {
  141. port = 8080;
  142. redirect_code = R"(
  143. "redirect_max": 2,)";
  144. }
  145. else if (get_client_protocol_type(config) == PROTOCOL_TYPE_REDIS)
  146. {
  147. port = 6379;
  148. user_and_passwd = R"(,
  149. "user_name": "root",
  150. "password": "")";
  151. }
  152. else if (get_client_protocol_type(config) == PROTOCOL_TYPE_MYSQL)
  153. port = 3306;
  154. else
  155. port = 1412;
  156. // for proxy
  157. if (config->type == COMMAND_PROXY)
  158. {
  159. if (get_client_protocol_type(config) == PROTOCOL_TYPE_HTTP)
  160. port = 8888;
  161. else
  162. port = port - 1;
  163. }
  164. size_t len = fprintf(out, format.c_str(), port,
  165. redirect_code.c_str(), user_and_passwd.c_str());
  166. return len > 0;
  167. }
  168. bool basic_server_transform(const std::string& format, FILE *out,
  169. const struct srpc_config *config)
  170. {
  171. uint8_t server_type = get_server_protocol_type(config);
  172. const char *type = get_type_string(server_type);
  173. size_t len = fprintf(out, format.c_str(), type, type,
  174. server_process_codes(server_type).c_str(),
  175. type, type);
  176. return len > 0;
  177. }
  178. bool basic_client_transform(const std::string& format, FILE *out,
  179. const struct srpc_config *config)
  180. {
  181. uint8_t client_type = get_client_protocol_type(config);
  182. const char *type = get_type_string(client_type);
  183. std::string client_lower = type;
  184. std::transform(client_lower.begin(), client_lower.end(),
  185. client_lower.begin(), ::tolower);
  186. std::string client_request_codes;
  187. if ((config->type == COMMAND_PROXY && client_type == PROTOCOL_TYPE_HTTP) ||
  188. config->type == COMMAND_REDIS)
  189. client_request_codes = client_set_request_codes(client_type);
  190. size_t len = fprintf(out, format.c_str(), type, type, type,
  191. client_task_callback_codes(client_type).c_str(),
  192. client_lower.c_str(),
  193. username_passwd_codes(client_type).c_str(),
  194. type, client_lower.c_str(),
  195. client_redirect_codes(client_type).c_str(),
  196. client_request_codes.c_str());
  197. return len > 0;
  198. }
  199. static void basic_default_file_initialize(DEFAULT_FILES& files)
  200. {
  201. struct CommandController::file_info info;
  202. info = { "basic/server.conf", "server.conf", basic_server_config_transform };
  203. files.push_back(info);
  204. info = { "basic/client.conf", "client.conf", basic_client_config_transform };
  205. files.push_back(info);
  206. info = { "basic/server_main.cc", "server_main.cc", basic_server_transform };
  207. files.push_back(info);
  208. info = { "basic/client_main.cc", "client_main.cc", basic_client_transform };
  209. files.push_back(info);
  210. info = { "common/config.json", "full.conf", nullptr };
  211. files.push_back(info);
  212. info = { "common/util.h", "config/util.h", nullptr };
  213. files.push_back(info);
  214. info = { "common/CMakeLists.txt", "CMakeLists.txt", common_cmake_transform };
  215. files.push_back(info);
  216. info = { "common/GNUmakefile", "GNUmakefile", nullptr };
  217. files.push_back(info);
  218. info = { "config/Json.h", "config/Json.h", nullptr };
  219. files.push_back(info);
  220. info = { "config/Json.cc", "config/Json.cc", nullptr };
  221. files.push_back(info);
  222. info = { "config/config_simple.h", "config/config.h", nullptr };
  223. files.push_back(info);
  224. info = { "config/config_simple.cc", "config/config.cc", nullptr };
  225. files.push_back(info);
  226. }
  227. static bool get_opt_args(int argc, const char **argv, struct srpc_config *config)
  228. {
  229. int c;
  230. while ((c = getopt(argc, (char * const *)argv, "o:t:d:")) >= 0)
  231. {
  232. switch (c)
  233. {
  234. case 'o':
  235. if (sscanf(optarg, "%s", config->output_path) != 1)
  236. return false;
  237. break;
  238. case 't':
  239. if (sscanf(optarg, "%s", config->template_path) != 1)
  240. return false; //TODO:
  241. break;
  242. case 'd':
  243. config->specified_depend_path = true;
  244. memset(config->depend_path, 0, MAXPATHLEN);
  245. if (sscanf(optarg, "%s", config->depend_path) != 1)
  246. return false;
  247. break;
  248. default:
  249. printf(COLOR_RED"Error:\n Unknown args : "
  250. COLOR_BLUE"%s\n\n" COLOR_OFF, argv[optind - 1]);
  251. return false;
  252. }
  253. }
  254. return true;
  255. }
  256. static bool basic_get_opt(int argc, const char **argv, struct srpc_config *config)
  257. {
  258. optind = 2;
  259. if (get_opt_args(argc, argv, config) == false)
  260. return false;
  261. if (optind == argc)
  262. {
  263. printf(COLOR_RED "Missing: PROJECT_NAME\n\n" COLOR_OFF);
  264. return false;
  265. }
  266. config->project_name = argv[optind];
  267. optind++;
  268. if (get_opt_args(argc, argv, config) == false)
  269. return false;
  270. if (config->project_name == NULL)
  271. {
  272. printf(COLOR_RED "Missing: PROJECT_NAME\n\n" COLOR_OFF);
  273. return false;
  274. }
  275. return true;
  276. }
  277. static void basic_print_usage(const char *name, const char *command)
  278. {
  279. printf(COLOR_PINK"Usage:\n"
  280. COLOR_INFO" %s " COLOR_COMMAND "%s "
  281. COLOR_INFO"<PROJECT_NAME>" COLOR_FLAG " [FLAGS]\n\n"
  282. COLOR_PINK"Example:\n"
  283. COLOR_PURPLE" %s %s my_%s_project\n\n"
  284. COLOR_PINK"Available Flags:\n"
  285. COLOR_FLAG" -o : "
  286. COLOR_WHITE"project output path (default: CURRENT_PATH)\n"
  287. COLOR_FLAG" -d : "
  288. COLOR_WHITE"path of dependencies (default: COMPILE_PATH)\n"
  289. COLOR_OFF, name, command, name, command, command);
  290. }
  291. HttpController::HttpController()
  292. {
  293. this->config.type = COMMAND_HTTP;
  294. basic_default_file_initialize(this->default_files);
  295. }
  296. void HttpController::print_usage(const char *name) const
  297. {
  298. basic_print_usage(name, "http");
  299. }
  300. bool HttpController::get_opt(int argc, const char **argv)
  301. {
  302. return basic_get_opt(argc, argv, &this->config);
  303. }
  304. RedisController::RedisController()
  305. {
  306. this->config.type = COMMAND_REDIS;
  307. basic_default_file_initialize(this->default_files);
  308. }
  309. void RedisController::print_usage(const char *name) const
  310. {
  311. basic_print_usage(name, "redis");
  312. }
  313. bool RedisController::get_opt(int argc, const char **argv)
  314. {
  315. return basic_get_opt(argc, argv, &this->config);
  316. }
  317. FileServiceController::FileServiceController()
  318. {
  319. this->config.type = COMMAND_FILE;
  320. struct file_info info;
  321. info = { "file/server.conf", "server.conf", nullptr };
  322. this->default_files.push_back(info);
  323. info = { "file/server_main.cc", "server_main.cc", nullptr };
  324. this->default_files.push_back(info);
  325. info = { "file/file_service.cc", "file_service.cc", nullptr };
  326. this->default_files.push_back(info);
  327. info = { "file/file_service.h", "file_service.h", nullptr };
  328. this->default_files.push_back(info);
  329. info = { "file/index.html", "html/index.html", nullptr };
  330. this->default_files.push_back(info);
  331. info = { "file/404.html", "html/404.html", nullptr };
  332. this->default_files.push_back(info);
  333. info = { "file/50x.html", "html/50x.html", nullptr };
  334. this->default_files.push_back(info);
  335. info = { "common/CMakeLists.txt", "CMakeLists.txt", common_cmake_transform };
  336. this->default_files.push_back(info);
  337. info = { "common/GNUmakefile", "GNUmakefile", nullptr };
  338. this->default_files.push_back(info);
  339. info = { "config/Json.h", "config/Json.h", nullptr };
  340. this->default_files.push_back(info);
  341. info = { "config/Json.cc", "config/Json.cc", nullptr };
  342. this->default_files.push_back(info);
  343. info = { "config/config_simple.h", "config/config.h", nullptr };
  344. this->default_files.push_back(info);
  345. info = { "config/config_simple.cc", "config/config.cc", nullptr };
  346. this->default_files.push_back(info);
  347. }
  348. void FileServiceController::print_usage(const char *name) const
  349. {
  350. basic_print_usage(name, "file");
  351. }
  352. bool FileServiceController::get_opt(int argc, const char **argv)
  353. {
  354. return basic_get_opt(argc, argv, &this->config);
  355. }
  356. void FileServiceController::print_success_info() const
  357. {
  358. printf(COLOR_GREEN"Success:\n make project path "
  359. COLOR_BLUE"\" %s \"" COLOR_GREEN "done.\n\n",
  360. this->config.output_path);
  361. printf(COLOR_PINK"Commands:\n " COLOR_BLUE "cd %s\n make -j\n\n",
  362. this->config.output_path);
  363. printf(COLOR_PINK"Execute:\n " COLOR_GREEN "./server\n\n");
  364. printf(COLOR_PINK"Try file service:\n");
  365. printf(COLOR_WHITE" curl localhost:8080/index.html\n");
  366. printf(" curl -i localhost:8080/a/b/\n\n" COLOR_OFF);
  367. }
  368. ComputeController::ComputeController()
  369. {
  370. this->config.type = COMMAND_COMPUTE;
  371. struct CommandController::file_info info;
  372. info = { "basic/server.conf", "server.conf", basic_server_config_transform };
  373. this->default_files.push_back(info);
  374. info = { "basic/compute_server_main.cc", "server_main.cc", nullptr };
  375. this->default_files.push_back(info);
  376. info = { "common/CMakeLists.txt", "CMakeLists.txt", common_cmake_transform };
  377. this->default_files.push_back(info);
  378. info = { "common/GNUmakefile", "GNUmakefile", nullptr };
  379. this->default_files.push_back(info);
  380. info = { "config/Json.h", "config/Json.h", nullptr };
  381. this->default_files.push_back(info);
  382. info = { "config/Json.cc", "config/Json.cc", nullptr };
  383. this->default_files.push_back(info);
  384. info = { "config/config_simple.h", "config/config.h", nullptr };
  385. this->default_files.push_back(info);
  386. info = { "config/config_simple.cc", "config/config.cc", nullptr };
  387. this->default_files.push_back(info);
  388. }
  389. void ComputeController::print_usage(const char *name) const
  390. {
  391. basic_print_usage(name, "compute");
  392. }
  393. bool ComputeController::get_opt(int argc, const char **argv)
  394. {
  395. return basic_get_opt(argc, argv, &this->config);
  396. }
  397. void ComputeController::print_success_info() const
  398. {
  399. printf(COLOR_GREEN"Success:\n make project path "
  400. COLOR_BLUE"\" %s \"" COLOR_GREEN " done.\n\n",
  401. this->config.output_path);
  402. printf(COLOR_PINK"Commands:\n " COLOR_BLUE "cd %s\n make -j\n\n",
  403. this->config.output_path);
  404. printf(COLOR_PINK"Execute:\n " COLOR_GREEN "./server\n\n");
  405. printf(COLOR_PINK"Try compute with n=8:\n");
  406. printf(COLOR_WHITE" curl localhost:8080/8\n\n" COLOR_OFF);
  407. }