srpc_config.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  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 <string.h>
  15. #include <stdlib.h>
  16. #include <string>
  17. #include <vector>
  18. #include <sys/stat.h>
  19. #include <sys/types.h>
  20. #include "srpc_config.h"
  21. std::vector<std::string> RPC_PROTOC_SKIP_FILES =
  22. { "config_simple.h", "config_simple.cc",
  23. "rpc.thrift", "client_thrift.cc", "server_thrift.cc" };
  24. std::vector<std::string> RPC_THRIFT_SKIP_FILES =
  25. { "config_simple.h", "config_simple.cc",
  26. "rpc.proto", "client_protobuf.cc", "server_protobuf.cc" };
  27. void usage_kafka(int argc, const char *argv[])
  28. {
  29. printf("Usage:\n"
  30. " %s kafka <PROJECT_NAME> [FLAGS]\n\n"
  31. "Available Flags:\n"
  32. " -o : project output path (default: CURRENT_PATH)\n"
  33. " -h : kafka broker url (example: kafka://10.160.23.23:9000,"
  34. "10.123.23.23,kafka://kafka.sogou)\n"
  35. " -g : group name\n"
  36. " -d : path of dependencies (default: COMPILE_PATH)\n"
  37. , argv[0]);
  38. }
  39. const char *get_type_string(uint8_t type)
  40. {
  41. switch (type)
  42. {
  43. case PROTOCOL_TYPE_HTTP:
  44. return "Http";
  45. case PROTOCOL_TYPE_REDIS:
  46. return "Redis";
  47. case PROTOCOL_TYPE_MYSQL:
  48. return "MySQL";
  49. case PROTOCOL_TYPE_KAFKA:
  50. return "Kafka";
  51. case PROTOCOL_TYPE_SRPC:
  52. return "SRPC";
  53. case PROTOCOL_TYPE_SRPC_HTTP:
  54. return "SRPCHttp";
  55. case PROTOCOL_TYPE_BRPC:
  56. return "BRPC";
  57. case PROTOCOL_TYPE_THRIFT:
  58. return "Thrift";
  59. case PROTOCOL_TYPE_THRIFT_HTTP:
  60. return "ThriftHttp";
  61. case PROTOCOL_TYPE_TRPC:
  62. return "TRPC";
  63. case PROTOCOL_TYPE_TRPC_HTTP:
  64. return "TRPCHttp";
  65. default:
  66. return "Unknown type";
  67. }
  68. }
  69. static int check_file_idl_type(const char *filename)
  70. {
  71. size_t len = strlen(filename);
  72. if (len > 6 && strcmp(filename + len - 6, ".proto") == 0)
  73. return IDL_TYPE_PROTOBUF;
  74. else if (len > 7 && strcmp(filename + len - 7, ".thrift") == 0)
  75. return IDL_TYPE_THRIFT;
  76. return IDL_TYPE_MAX;
  77. }
  78. srpc_config::srpc_config()
  79. {
  80. project_name = NULL;
  81. service_name = NULL;
  82. rpc_type = PROTOCOL_TYPE_SRPC;
  83. idl_type = IDL_TYPE_DEFAULT;
  84. data_type = DATA_TYPE_DEFAULT;
  85. compress_type = COMPRESS_TYPE_NONE;
  86. specified_depend_path = false;
  87. specified_idl_file = NULL;
  88. specified_idl_path = NULL;
  89. }
  90. bool srpc_config::prepare_specified_idl_file()
  91. {
  92. if (this->specified_idl_file == NULL)
  93. {
  94. if (this->specified_idl_path != NULL)
  95. {
  96. printf(COLOR_RED"Error:\n idl_path is specified "
  97. "but NO idl_file.\n\n" COLOR_OFF);
  98. return false;
  99. }
  100. return true;
  101. }
  102. else if (this->service_name != NULL)
  103. {
  104. printf(COLOR_RED"Error:\n [-s service_name] does NOT take effect "
  105. "when idl_file is specified.\n\n" COLOR_OFF);
  106. return false;
  107. }
  108. this->idl_type = check_file_idl_type(this->specified_idl_file);
  109. if (this->idl_type == IDL_TYPE_MAX)
  110. {
  111. printf(COLOR_RED"Error:\n Invalid idl type. file :" COLOR_BLUE
  112. " %s\n\n" COLOR_OFF, this->specified_idl_file);
  113. return false;
  114. }
  115. if (access(this->specified_idl_file, F_OK) != 0)
  116. {
  117. printf(COLOR_RED"Error:\n idl_file" COLOR_BLUE " %s " COLOR_RED
  118. "does NOT exist.\n\n" COLOR_OFF, this->specified_idl_file);
  119. return false;
  120. }
  121. if (this->specified_idl_path == NULL)
  122. this->specified_idl_path = this->output_path;
  123. return true;
  124. }
  125. const char *srpc_config::rpc_type_string() const
  126. {
  127. return get_type_string(this->rpc_type);
  128. }
  129. const char *srpc_config::rpc_compress_string() const
  130. {
  131. switch (this->compress_type)
  132. {
  133. case COMPRESS_TYPE_SNAPPY:
  134. return "RPCCompressSnappy";
  135. case COMPRESS_TYPE_GZIP:
  136. return "RPCCompressGzip";
  137. case COMPRESS_TYPE_ZLIB:
  138. return "RPCCompressZlib";
  139. case COMPRESS_TYPE_LZ4:
  140. return "RPCCompressLz4";
  141. default:
  142. return "Unknown type";
  143. }
  144. }
  145. const char *srpc_config::rpc_data_string() const
  146. {
  147. switch (this->data_type)
  148. {
  149. case DATA_TYPE_PROTOBUF:
  150. return "RPCDataProtobuf";
  151. case DATA_TYPE_THRIFT:
  152. return "RPCDataThrift";
  153. case DATA_TYPE_JSON:
  154. return "RPCDataJson";
  155. default:
  156. return "Unknown type";
  157. }
  158. }
  159. void srpc_config::set_rpc_type(const char *type)
  160. {
  161. if (strcasecmp(type, "SRPCHttp") == 0)
  162. this->rpc_type = PROTOCOL_TYPE_SRPC_HTTP;
  163. else if (strcasecmp(type, "SRPC") == 0)
  164. this->rpc_type = PROTOCOL_TYPE_SRPC;
  165. else if (strcasecmp(type, "BRPC") == 0)
  166. this->rpc_type = PROTOCOL_TYPE_BRPC;
  167. else if (strcasecmp(type, "ThriftHttp") == 0)
  168. this->rpc_type = PROTOCOL_TYPE_THRIFT_HTTP;
  169. else if (strcasecmp(type, "Thrift") == 0)
  170. this->rpc_type = PROTOCOL_TYPE_THRIFT;
  171. else if (strcasecmp(type, "TRPCHttp") == 0)
  172. this->rpc_type = PROTOCOL_TYPE_TRPC_HTTP;
  173. else if (strcasecmp(type, "TRPC") == 0)
  174. this->rpc_type = PROTOCOL_TYPE_TRPC;
  175. else
  176. this->rpc_type = PROTOCOL_TYPE_MAX;
  177. }
  178. void srpc_config::set_idl_type(const char *type)
  179. {
  180. if (strcasecmp(type, "protobuf") == 0)
  181. this->idl_type = IDL_TYPE_PROTOBUF;
  182. else if (strcasecmp(type, "thrift") == 0)
  183. this->idl_type = IDL_TYPE_THRIFT;
  184. else
  185. this->idl_type = IDL_TYPE_MAX;
  186. }
  187. void srpc_config::set_data_type(const char *type)
  188. {
  189. if (strcasecmp(type, "protobuf") == 0)
  190. this->data_type = DATA_TYPE_PROTOBUF;
  191. else if (strcasecmp(type, "thrift") == 0)
  192. this->data_type = DATA_TYPE_THRIFT;
  193. else if (strcasecmp(type, "json") == 0)
  194. this->data_type = DATA_TYPE_JSON;
  195. else
  196. this->data_type = DATA_TYPE_MAX;
  197. }
  198. void srpc_config::set_compress_type(const char *type)
  199. {
  200. if (strcasecmp(type, "snappy") == 0)
  201. this->compress_type = COMPRESS_TYPE_SNAPPY;
  202. else if (strcasecmp(type, "gzip") == 0)
  203. this->compress_type = COMPRESS_TYPE_GZIP;
  204. else if (strcasecmp(type, "zlib") == 0)
  205. this->compress_type = COMPRESS_TYPE_ZLIB;
  206. else if (strcasecmp(type, "lz4") == 0)
  207. this->compress_type = COMPRESS_TYPE_LZ4;
  208. else
  209. this->compress_type = COMPRESS_TYPE_MAX;
  210. }
  211. const char *srpc_config::proxy_server_type_string() const
  212. {
  213. return get_type_string(this->proxy_server_type);
  214. }
  215. const char *srpc_config::proxy_client_type_string() const
  216. {
  217. return get_type_string(this->proxy_client_type);
  218. }
  219. int check_proxy_type(uint8_t type)
  220. {
  221. if (type == PROTOCOL_TYPE_HTTP ||
  222. type == PROTOCOL_TYPE_REDIS ||
  223. type == PROTOCOL_TYPE_MYSQL ||
  224. type == PROTOCOL_TYPE_KAFKA)
  225. return PROXY_BASIC_TYPE;
  226. if (type == PROTOCOL_TYPE_SRPC ||
  227. type == PROTOCOL_TYPE_SRPC_HTTP ||
  228. type == PROTOCOL_TYPE_BRPC ||
  229. type == PROTOCOL_TYPE_TRPC ||
  230. type == PROTOCOL_TYPE_TRPC_HTTP)
  231. return PROXY_PROTOBUF_TYPE;
  232. if (type == PROTOCOL_TYPE_THRIFT ||
  233. type == PROTOCOL_TYPE_THRIFT_HTTP)
  234. return PROXY_THRIFT_TYPE;
  235. return -1;
  236. }
  237. ControlGenerator::ControlGenerator(const struct srpc_config *config) :
  238. Generator(config->idl_type == IDL_TYPE_THRIFT ? true : false),
  239. ctl_printer(config->idl_type == IDL_TYPE_THRIFT ? true : false),
  240. config(config)
  241. { }
  242. bool ControlGenerator::generate_client_cpp_file(const idl_info& info,
  243. const std::string& idl_file)
  244. {
  245. this->client_cpp_file = this->config->output_path;
  246. this->client_cpp_file += "client_main.cc";
  247. if (this->ctl_printer.open(this->client_cpp_file) == false)
  248. return false;
  249. this->ctl_printer.print_clt_include();
  250. this->ctl_printer.print_client_file_include(idl_file);
  251. for (const auto& desc : info.desc_list)
  252. {
  253. if (desc.block_type != "service")
  254. continue;
  255. for (const auto& rpc : desc.rpcs)
  256. {
  257. this->ctl_printer.print_client_done_method_ctl(info.package_name,
  258. desc.block_name,
  259. rpc.method_name,
  260. rpc.response_name);
  261. }
  262. }
  263. this->ctl_printer.print_client_main_begin();
  264. this->ctl_printer.print_client_load_config();
  265. this->ctl_printer.print_client_params();
  266. int id = 0;
  267. for (const auto& desc : info.desc_list)
  268. {
  269. if (desc.block_type != "service")
  270. continue;
  271. std::string suffix;
  272. if (id != 0)
  273. suffix = std::to_string(id);
  274. id++;
  275. this->ctl_printer.print_client_main_service_ctl(this->config->rpc_type_string(),
  276. info.package_name,
  277. desc.block_name,
  278. suffix);
  279. auto rpc_it = desc.rpcs.cbegin();
  280. if (rpc_it != desc.rpcs.cend())
  281. {
  282. this->ctl_printer.print_client_main_method_call(info.package_name,
  283. desc.block_name,
  284. rpc_it->method_name,
  285. rpc_it->request_name,
  286. suffix);
  287. rpc_it++;
  288. }
  289. }
  290. this->ctl_printer.print_client_main_end();
  291. this->ctl_printer.close();
  292. return false;
  293. }
  294. bool ControlGenerator::generate_server_cpp_file(const idl_info& info,
  295. const std::string& idl_file)
  296. {
  297. this->server_cpp_file = this->config->output_path;
  298. this->server_cpp_file += "server_main.cc";
  299. if (this->ctl_printer.open(this->server_cpp_file) == false)
  300. return false;
  301. this->ctl_printer.print_clt_include();
  302. this->ctl_printer.print_server_file_include(idl_file);
  303. for (const auto& desc : info.desc_list)
  304. {
  305. if (desc.block_type != "service")
  306. continue;
  307. this->ctl_printer.print_server_class_impl(info.package_name,
  308. desc.block_name);
  309. for (const auto& rpc : desc.rpcs)
  310. {
  311. this->ctl_printer.print_server_impl_method(info.package_name,
  312. desc.block_name,
  313. rpc.method_name,
  314. rpc.request_name,
  315. rpc.response_name);
  316. }
  317. this->ctl_printer.print_server_class_impl_end();
  318. }
  319. this->ctl_printer.print_server_main_begin();
  320. this->ctl_printer.print_server_load_config();
  321. this->ctl_printer.print_server_construct(this->config->rpc_type_string());
  322. for (const auto& desc : info.desc_list)
  323. {
  324. if (desc.block_type != "service")
  325. continue;
  326. this->ctl_printer.print_server_main_method(desc.block_name);
  327. }
  328. this->ctl_printer.print_server_main_end_ctl(this->config->project_name,
  329. this->config->rpc_type_string());
  330. this->ctl_printer.print_server_main_return();
  331. this->ctl_printer.close();
  332. return true;
  333. }
  334. static std::string ctl_include_format = R"(#include <stdio.h>
  335. #include "config/config.h"
  336. )";
  337. static std::string ctl_load_config_format = R"(
  338. // load config
  339. srpc::RPCConfig config;
  340. if (config.load("./%s") == false)
  341. {
  342. perror("Load config failed");
  343. exit(1);
  344. }
  345. signal(SIGINT, sig_handler);
  346. )";
  347. static std::string ctl_client_load_params_format = R"(
  348. // start client
  349. RPCClientParams params = RPC_CLIENT_PARAMS_DEFAULT;
  350. params.host = config.client_host();
  351. params.port = config.client_port();
  352. )";
  353. static std::string ctl_client_main_params_format = R"(
  354. %s::%sClient client%s(&params);
  355. config.load_filter(client%s);
  356. )";
  357. static std::string ctl_client_done_protobuf_format = R"(
  358. // printf("%%s\n", response->DebugString().c_str());
  359. )";
  360. static std::string ctl_client_done_format = R"(
  361. static void %s_done(%s *response, srpc::RPCContext *context)
  362. {
  363. if (context->success())
  364. {
  365. // TODO: fill your logic to set response%s
  366. }
  367. else
  368. printf("%s %s status[%%d] error[%%d] errmsg:%%s\n",
  369. context->get_status_code(), context->get_error(),
  370. context->get_errmsg());
  371. }
  372. )";
  373. static std::string ctl_server_main_end_format = R"(
  374. config.load_filter(server);
  375. if (server.start(config.server_port()) == 0)
  376. {
  377. printf("%s %s server started, port %%u\n", config.server_port());
  378. wait_group.wait();
  379. server.stop();
  380. }
  381. else
  382. perror("server start");
  383. )";
  384. void ControlGenerator::ControlPrinter::print_clt_include()
  385. {
  386. fprintf(this->out_file, "%s", ctl_include_format.c_str());
  387. }
  388. void ControlGenerator::ControlPrinter::print_client_load_config()
  389. {
  390. fprintf(this->out_file, ctl_load_config_format.c_str(), "./client.conf");
  391. }
  392. void ControlGenerator::ControlPrinter::print_server_load_config()
  393. {
  394. fprintf(this->out_file, ctl_load_config_format.c_str(), "./server.conf");
  395. }
  396. void ControlGenerator::ControlPrinter::print_client_params()
  397. {
  398. fprintf(this->out_file, "%s", ctl_client_load_params_format.c_str());
  399. fprintf(this->out_file, "\tparams.is_ssl = config.client_is_ssl();\n");
  400. fprintf(this->out_file, "\tparams.url = config.client_url();\n");
  401. fprintf(this->out_file, "\tparams.caller = config.client_caller();\n");
  402. // TODO: set client task params
  403. }
  404. void ControlGenerator::ControlPrinter::
  405. print_client_done_method_ctl(const std::vector<std::string>& package,
  406. const std::string& service,
  407. const std::string& method,
  408. const std::string& response)
  409. {
  410. std::string method_lower = method;
  411. std::transform(method_lower.begin(), method_lower.end(),
  412. method_lower.begin(), ::tolower);
  413. std::string resp;
  414. const char *set_resp_code = "";
  415. if (this->is_thrift)
  416. resp = make_thrift_package_prefix(package, service, response);
  417. else
  418. resp = make_package_prefix(package, response);
  419. if (!this->is_thrift)
  420. set_resp_code = ctl_client_done_protobuf_format.c_str();
  421. fprintf(this->out_file, ctl_client_done_format.c_str(),
  422. method_lower.c_str(), resp.c_str(), set_resp_code,
  423. service.c_str(), method.c_str(), service.c_str(), method.c_str());
  424. }
  425. void ControlGenerator::ControlPrinter::
  426. print_client_main_service_ctl(const std::string& type,
  427. const std::vector<std::string>& package,
  428. const std::string& service,
  429. const std::string& suffix)
  430. {
  431. std::string base_service = make_package_prefix(package, service);
  432. fprintf(this->out_file, ctl_client_main_params_format.c_str(),
  433. base_service.c_str(), type.c_str(),
  434. suffix.c_str(), suffix.c_str());
  435. }
  436. void ControlGenerator::ControlPrinter::
  437. print_server_construct(const char *rpc_type)
  438. {
  439. fprintf(this->out_file, " %sServer server;\n", rpc_type);
  440. }
  441. void ControlGenerator::ControlPrinter::
  442. print_server_main_end_ctl(const char *project_name, const char *rpc_type)
  443. {
  444. fprintf(this->out_file, ctl_server_main_end_format.c_str(),
  445. project_name, rpc_type);
  446. }