generator.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. /*
  2. Copyright (c) 2020 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 "generator.h"
  14. bool Generator::init_file_names(const std::string& idl_file, const char *out_dir)
  15. {
  16. if (idl_file.size() <= 5)
  17. return false;
  18. const char *p;
  19. if (this->is_thrift)
  20. {
  21. p = idl_file.c_str() + idl_file.size() - 7;
  22. if (strncmp(p, ".thrift", 7) != 0)
  23. return false;
  24. }
  25. else
  26. {
  27. p = idl_file.c_str() + idl_file.size() - 6;
  28. if (strncmp(p, ".proto", 6) != 0)
  29. return false;
  30. }
  31. p = idl_file.c_str() + idl_file.size() - 1;
  32. while (p > idl_file.c_str())
  33. {
  34. if (*p == '/')
  35. break;
  36. p--;
  37. }
  38. if (*p == '/')
  39. p++;
  40. std::string str = p;
  41. auto pos = str.find(".");
  42. if (pos == std::string::npos)
  43. return false;
  44. this->prefix = str.substr(0, pos);
  45. str = out_dir;
  46. if (str[str.length() - 1] != '/')
  47. str.append("/");
  48. this->out_dir = str;
  49. this->srpc_file = str;
  50. this->srpc_file.append(this->prefix);
  51. this->srpc_file.append(this->suffix);
  52. this->srpc_file.append("h");
  53. this->thrift_type_file = str;
  54. this->thrift_type_file.append(this->prefix);
  55. this->thrift_type_file.append(this->thrift_suffix);
  56. this->thrift_type_file.append("h");
  57. fprintf(stdout, "[Generator] generate srpc files: %s %s\n",
  58. this->srpc_file.c_str(),
  59. this->is_thrift ? this->thrift_type_file.c_str() : "");
  60. return true;
  61. }
  62. bool Generator::generate(struct GeneratorParams& params)
  63. {
  64. this->info.input_dir = params.input_dir;
  65. if (this->parser.parse(params.idl_file, this->info) == false)
  66. {
  67. fprintf(stderr, "[Generator Error] parse failed.\n");
  68. return false;
  69. }
  70. if (this->generate_header(this->info, params) == false)
  71. {
  72. fprintf(stderr, "[Generator Error] generate failed.\n");
  73. return false;
  74. }
  75. if (params.generate_skeleton == true)
  76. this->generate_skeleton(this->info.file_name);
  77. return true;
  78. }
  79. bool Generator::generate_header(idl_info& cur_info, struct GeneratorParams& params)
  80. {
  81. for (auto& sub_info : cur_info.include_list)
  82. {
  83. fprintf(stdout, "[Generator] auto generate include file [%s]\n",
  84. sub_info.absolute_file_path.c_str());
  85. if (!this->generate_header(sub_info, params))
  86. return false;
  87. }
  88. // for protobuf: if no [rpc], don`t need to generate xxx.srpc.h
  89. if (this->init_file_names(cur_info.absolute_file_path, params.out_dir) == false)
  90. {
  91. fprintf(stderr, "[Generator Error] init file name failed. %s %s\n",
  92. cur_info.absolute_file_path.c_str(), params.out_dir);
  93. return false;
  94. }
  95. // will generate skeleton file only once
  96. if (this->is_thrift)
  97. {
  98. //[prefix].thrift.h
  99. if (!this->generate_thrift_type_file(cur_info))
  100. {
  101. fprintf(stderr, "[Generator Error] generate thrift type file failed.\n");
  102. return false;
  103. }
  104. }
  105. for (const auto& desc : this->info.desc_list)
  106. {
  107. if (desc.block_type == "service")
  108. {
  109. //has_service = true;
  110. if (!this->generate_srpc_file(cur_info)) // [prefix].srpc.h
  111. {
  112. fprintf(stderr, "[Generator Error] generate srpc file failed.\n");
  113. return false;
  114. }
  115. break;
  116. }
  117. }
  118. fprintf(stdout, "[Generator Done]\n");
  119. return true;
  120. }
  121. void Generator::generate_skeleton(const std::string& idl_file)
  122. {
  123. const char *p;
  124. if (this->is_thrift)
  125. {
  126. p = idl_file.c_str() + idl_file.size() - 7;
  127. if (strncmp(p, ".thrift", 7) != 0)
  128. return;
  129. }
  130. else
  131. {
  132. p = idl_file.c_str() + idl_file.size() - 6;
  133. if (strncmp(p, ".proto", 6) != 0)
  134. return;
  135. }
  136. p = idl_file.c_str() + idl_file.size() - 1;
  137. while (p > idl_file.c_str())
  138. {
  139. if (*p == '/')
  140. break;
  141. p--;
  142. }
  143. if (*p == '/')
  144. p++;
  145. std::string str = p;
  146. auto pos = str.find(".");
  147. if (pos == std::string::npos)
  148. return;
  149. std::string idl_file_name = str.substr(0, pos);
  150. // server.skeleton.cc
  151. this->generate_server_cpp_file(this->info, idl_file_name);
  152. // client.skeleton.cc
  153. this->generate_client_cpp_file(this->info, idl_file_name);
  154. fprintf(stdout, "[Generator] generate server files: %s, client files: %s\n",
  155. this->server_cpp_file.c_str(),
  156. this->client_cpp_file.c_str());
  157. return;
  158. }
  159. void Generator::thrift_replace_include(const idl_info& cur_info, std::vector<rpc_param>& params)
  160. {
  161. for (auto& param : params)
  162. {
  163. if (param.data_type == srpc::TDT_LIST
  164. || param.data_type == srpc::TDT_MAP
  165. || param.data_type == srpc::TDT_SET)
  166. {
  167. for (const auto& desc : cur_info.desc_list)
  168. {
  169. if (desc.block_type == "enum")
  170. SGenUtil::replace(param.type_name, desc.block_name, "int32_t");
  171. }
  172. for (const auto& sub_info : cur_info.include_list)
  173. {
  174. for (const auto& desc : sub_info.desc_list)
  175. {
  176. if (desc.block_type == "enum")
  177. SGenUtil::replace(param.type_name, sub_info.file_name_prefix + desc.block_name, "int32_t");
  178. }
  179. }
  180. }
  181. auto pos = param.type_name.find('.');
  182. if (pos != std::string::npos)
  183. {
  184. for (const auto& sub_info : cur_info.include_list)
  185. {
  186. if (sub_info.package_name.empty())
  187. continue;
  188. //printf("????%s %s\n", sub_info.file_name_prefix.c_str(), sub_info.package_name.c_str());
  189. SGenUtil::replace(param.type_name, sub_info.file_name_prefix,
  190. "::" + join_package_names(sub_info.package_name) + "::");
  191. }
  192. }
  193. }
  194. }
  195. bool Generator::generate_thrift_type_file(idl_info& cur_info)
  196. {
  197. if (!this->printer.open(this->thrift_type_file))
  198. {
  199. fprintf(stderr, "[Generator Error] can't write to thirft_type_file: %s.\n",
  200. this->thrift_type_file.c_str());
  201. return false;
  202. }
  203. this->printer.print_thrift_include(cur_info);
  204. this->printer.print_thrift_struct_declaration(cur_info);
  205. this->printer.print_thrift_typedef(cur_info);
  206. for (auto& desc : cur_info.desc_list)
  207. {
  208. if (desc.block_type == "service")
  209. {
  210. this->printer.print_service_namespace(desc.block_name);
  211. for (auto& rpc : desc.rpcs)
  212. {
  213. this->thrift_replace_include(cur_info, rpc.req_params);
  214. this->printer.print_rpc_thrift_struct_class(rpc.request_name, rpc.req_params,cur_info);
  215. this->thrift_replace_include(cur_info, rpc.resp_params);
  216. this->printer.print_rpc_thrift_struct_class(rpc.response_name, rpc.resp_params,cur_info);
  217. }
  218. this->printer.print_service_namespace_end(desc.block_name);
  219. }
  220. else if (desc.block_type == "struct" || desc.block_type == "union")
  221. {
  222. this->thrift_replace_include(cur_info, desc.st.params);
  223. this->printer.print_rpc_thrift_struct_class(desc.block_name, desc.st.params,cur_info);
  224. }
  225. else if (desc.block_type == "enum")
  226. {
  227. this->printer.print_thrift_include_enum(desc.block_name, desc.enum_lines);
  228. }
  229. }
  230. this->printer.print_end(cur_info.package_name);
  231. this->printer.close();
  232. return true;
  233. }
  234. bool Generator::generate_srpc_file(const idl_info& cur_info)
  235. {
  236. if (!this->printer.open(this->srpc_file))
  237. {
  238. fprintf(stderr, "[Generator Error] can't write to srpc file: %s.\n",
  239. this->srpc_file.c_str());
  240. return false;
  241. }
  242. this->printer.print_srpc_include(this->prefix, cur_info.package_name);
  243. std::vector<std::string> rpc_list;
  244. std::string package;
  245. if (this->is_thrift)
  246. {
  247. rpc_list.push_back("SRPC");
  248. rpc_list.push_back("SRPCHttp");
  249. rpc_list.push_back("Thrift");
  250. rpc_list.push_back("ThriftHttp");
  251. }
  252. else
  253. {
  254. rpc_list.push_back("SRPC");
  255. rpc_list.push_back("SRPCHttp");
  256. rpc_list.push_back("BRPC");
  257. rpc_list.push_back("TRPC");
  258. rpc_list.push_back("TRPCHttp");
  259. }
  260. for (const std::string& p : cur_info.package_name)
  261. {
  262. package.append(p);
  263. package.push_back('.');
  264. }
  265. for (const auto& desc : cur_info.desc_list)
  266. {
  267. if (desc.block_type != "service")
  268. continue;
  269. this->printer.print_service_namespace(desc.block_name);
  270. this->printer.print_server_comment();
  271. if (this->is_thrift)
  272. this->printer.print_server_class_thrift(desc.block_name, desc.rpcs);
  273. else
  274. this->printer.print_server_class(desc.block_name, desc.rpcs);
  275. this->printer.print_client_comment();
  276. for (const auto& rpc : desc.rpcs)
  277. {
  278. this->printer.print_client_define_done(rpc.method_name,
  279. rpc.response_name);
  280. }
  281. this->printer.print_empty_line();
  282. for (const auto& type : rpc_list)
  283. this->printer.print_client_class(type, desc.block_name, desc.rpcs);
  284. this->printer.print_implement_comments();
  285. this->printer.print_server_constructor(package + desc.block_name, desc.rpcs);
  286. if (this->is_thrift)
  287. this->printer.print_server_methods_thrift(desc.block_name, desc.rpcs);
  288. for (const auto& type : rpc_list)
  289. {
  290. this->printer.print_client_constructor(type, desc.block_name,
  291. cur_info.package_name);
  292. this->printer.print_client_methods(type, desc.block_name, desc.rpcs,
  293. cur_info.package_name);
  294. this->printer.print_client_create_task(type, desc.block_name,
  295. desc.rpcs, cur_info.package_name);
  296. }
  297. this->printer.print_service_namespace_end(desc.block_name);
  298. }
  299. this->printer.print_end(cur_info.package_name);
  300. this->printer.close();
  301. return true;
  302. }
  303. bool Generator::generate_server_cpp_file(const idl_info& cur_info,
  304. const std::string& idl_file_name)
  305. {
  306. this->server_cpp_file = this->out_dir;
  307. this->server_cpp_file.append("server");
  308. this->server_cpp_file.append(this->is_thrift ? ".thrift_skeleton." : ".pb_skeleton.");
  309. this->server_cpp_file.append("cc");
  310. if (this->printer.open(this->server_cpp_file) == false)
  311. return false;
  312. this->printer.print_server_file_include(idl_file_name);
  313. for (const auto& desc : cur_info.desc_list)
  314. {
  315. if (desc.block_type != "service")
  316. continue;
  317. this->printer.print_server_class_impl(cur_info.package_name, desc.block_name);
  318. for (const auto& rpc : desc.rpcs)
  319. {
  320. this->printer.print_server_impl_method(cur_info.package_name,
  321. desc.block_name,
  322. rpc.method_name,
  323. rpc.request_name,
  324. rpc.response_name);
  325. }
  326. this->printer.print_server_class_impl_end();
  327. }
  328. this->printer.print_server_main_begin();
  329. this->printer.print_server_main_address();
  330. for (const auto& desc : cur_info.desc_list)
  331. {
  332. if (desc.block_type != "service")
  333. continue;
  334. this->printer.print_server_main_method(desc.block_name);
  335. }
  336. this->printer.print_server_main_end();
  337. this->printer.print_server_main_return();
  338. this->printer.close();
  339. return true;
  340. }
  341. bool Generator::generate_client_cpp_file(const idl_info& cur_info,
  342. const std::string& idl_file_name)
  343. {
  344. this->client_cpp_file = this->out_dir;
  345. this->client_cpp_file.append("client");
  346. this->client_cpp_file.append(this->is_thrift ? ".thrift_skeleton." : ".pb_skeleton.");
  347. this->client_cpp_file.append("cc");
  348. if (this->printer.open(this->client_cpp_file) == false)
  349. return false;
  350. this->printer.print_client_file_include(idl_file_name);
  351. for (const auto& desc : cur_info.desc_list)
  352. {
  353. if (desc.block_type != "service")
  354. continue;
  355. for (const auto& rpc : desc.rpcs)
  356. {
  357. this->printer.print_client_done_method(cur_info.package_name,
  358. desc.block_name,
  359. rpc.method_name,
  360. rpc.response_name);
  361. }
  362. }
  363. this->printer.print_client_main_begin();
  364. this->printer.print_client_main_address();
  365. int id = 0;
  366. for (const auto& desc : cur_info.desc_list)
  367. {
  368. if (desc.block_type != "service")
  369. continue;
  370. std::string suffix;
  371. if (id != 0)
  372. suffix = std::to_string(id);
  373. id++;
  374. if (this->is_thrift)
  375. this->printer.print_client_main_service("Thrift",
  376. cur_info.package_name, desc.block_name, suffix);
  377. else
  378. this->printer.print_client_main_service("SRPC",
  379. cur_info.package_name, desc.block_name, suffix);
  380. auto rpc_it = desc.rpcs.cbegin();
  381. if (rpc_it != desc.rpcs.cend())
  382. {
  383. this->printer.print_client_main_method_call(cur_info.package_name,
  384. desc.block_name,
  385. rpc_it->method_name,
  386. rpc_it->request_name,
  387. suffix);
  388. rpc_it++;
  389. //if (rpc_it == desc.rpcs.end())
  390. // rpc_it = desc.rpcs.begin();
  391. //this->printer.print_client_main_create_task(print_client_main_create_task, rpc_it->method_name,
  392. // rpc_it->request_name);
  393. }
  394. }
  395. this->printer.print_client_main_end();
  396. this->printer.close();
  397. return true;
  398. }