idl_gen_grpc.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * Copyright 2014 Google Inc. All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. // independent from idl_parser, since this code is not needed for most clients
  17. #include "flatbuffers/flatbuffers.h"
  18. #include "flatbuffers/idl.h"
  19. #include "flatbuffers/util.h"
  20. #include "flatbuffers/code_generators.h"
  21. #include "src/compiler/cpp_generator.h"
  22. #include "src/compiler/go_generator.h"
  23. namespace flatbuffers {
  24. class FlatBufMethod : public grpc_generator::Method {
  25. public:
  26. enum Streaming { kNone, kClient, kServer, kBiDi };
  27. FlatBufMethod(const RPCCall *method)
  28. : method_(method) {
  29. streaming_ = kNone;
  30. auto val = method_->attributes.Lookup("streaming");
  31. if (val) {
  32. if (val->constant == "client") streaming_ = kClient;
  33. if (val->constant == "server") streaming_ = kServer;
  34. if (val->constant == "bidi") streaming_ = kBiDi;
  35. }
  36. }
  37. std::string name() const { return method_->name; }
  38. std::string GRPCType(const StructDef &sd) const {
  39. return "flatbuffers::BufferRef<" + sd.name + ">";
  40. }
  41. std::string input_type_name() const {
  42. return GRPCType(*method_->request);
  43. }
  44. std::string output_type_name() const {
  45. return GRPCType(*method_->response);
  46. }
  47. std::string input_name() const {
  48. return (*method_->request).name;
  49. }
  50. std::string output_name() const {
  51. return (*method_->response).name;
  52. }
  53. bool NoStreaming() const { return streaming_ == kNone; }
  54. bool ClientOnlyStreaming() const { return streaming_ == kClient; }
  55. bool ServerOnlyStreaming() const { return streaming_ == kServer; }
  56. bool BidiStreaming() const { return streaming_ == kBiDi; }
  57. private:
  58. const RPCCall *method_;
  59. Streaming streaming_;
  60. };
  61. class FlatBufService : public grpc_generator::Service {
  62. public:
  63. FlatBufService(const ServiceDef *service) : service_(service) {}
  64. std::string name() const { return service_->name; }
  65. int method_count() const {
  66. return static_cast<int>(service_->calls.vec.size());
  67. };
  68. std::unique_ptr<const grpc_generator::Method> method(int i) const {
  69. return std::unique_ptr<const grpc_generator::Method>(
  70. new FlatBufMethod(service_->calls.vec[i]));
  71. };
  72. private:
  73. const ServiceDef *service_;
  74. };
  75. class FlatBufPrinter : public grpc_generator::Printer {
  76. public:
  77. FlatBufPrinter(std::string *str)
  78. : str_(str), escape_char_('$'), indent_(0) {}
  79. void Print(const std::map<std::string, std::string> &vars,
  80. const char *string_template) {
  81. std::string s = string_template;
  82. // Replace any occurrences of strings in "vars" that are surrounded
  83. // by the escape character by what they're mapped to.
  84. size_t pos;
  85. while ((pos = s.find(escape_char_)) != std::string::npos) {
  86. // Found an escape char, must also find the closing one.
  87. size_t pos2 = s.find(escape_char_, pos + 1);
  88. // If placeholder not closed, ignore.
  89. if (pos2 == std::string::npos) break;
  90. auto it = vars.find(s.substr(pos + 1, pos2 - pos - 1));
  91. // If unknown placeholder, ignore.
  92. if (it == vars.end()) break;
  93. // Subtitute placeholder.
  94. s.replace(pos, pos2 - pos + 1, it->second);
  95. }
  96. Print(s.c_str());
  97. }
  98. void Print(const char *s) {
  99. // Add this string, but for each part separated by \n, add indentation.
  100. for (;;) {
  101. // Current indentation.
  102. str_->insert(str_->end(), indent_ * 2, ' ');
  103. // See if this contains more than one line.
  104. const char * lf = strchr(s, '\n');
  105. if (lf) {
  106. (*str_) += std::string(s, lf + 1);
  107. s = lf + 1;
  108. if (!*s) break; // Only continue if there's more lines.
  109. } else {
  110. (*str_) += s;
  111. break;
  112. }
  113. }
  114. }
  115. void Indent() { indent_++; }
  116. void Outdent() { indent_--; assert(indent_ >= 0); }
  117. private:
  118. std::string *str_;
  119. char escape_char_;
  120. int indent_;
  121. };
  122. class FlatBufFile : public grpc_generator::File {
  123. public:
  124. FlatBufFile(const Parser &parser, const std::string &file_name)
  125. : parser_(parser), file_name_(file_name) {}
  126. FlatBufFile &operator=(const FlatBufFile &);
  127. std::string filename() const { return file_name_; }
  128. std::string filename_without_ext() const {
  129. return StripExtension(file_name_);
  130. }
  131. std::string message_header_ext() const { return "_generated.h"; }
  132. std::string service_header_ext() const { return ".grpc.fb.h"; }
  133. std::string package() const {
  134. return parser_.namespaces_.back()->GetFullyQualifiedName("");
  135. }
  136. std::vector<std::string> package_parts() const {
  137. return parser_.namespaces_.back()->components;
  138. }
  139. std::string additional_headers() const {
  140. return "#include \"flatbuffers/grpc.h\"\n";
  141. }
  142. std::string additional_imports() const {
  143. return "import \"github.com/google/flatbuffers/go\"";
  144. }
  145. int service_count() const {
  146. return static_cast<int>(parser_.services_.vec.size());
  147. };
  148. std::unique_ptr<const grpc_generator::Service> service(int i) const {
  149. return std::unique_ptr<const grpc_generator::Service> (
  150. new FlatBufService(parser_.services_.vec[i]));
  151. }
  152. std::unique_ptr<grpc_generator::Printer> CreatePrinter(std::string *str) const {
  153. return std::unique_ptr<grpc_generator::Printer>(
  154. new FlatBufPrinter(str));
  155. }
  156. private:
  157. const Parser &parser_;
  158. const std::string &file_name_;
  159. };
  160. class GoGRPCGenerator : public flatbuffers::BaseGenerator {
  161. public:
  162. GoGRPCGenerator(const Parser &parser, const std::string &path,
  163. const std::string &file_name)
  164. : BaseGenerator(parser, path, file_name, "", "" /*Unused*/),
  165. parser_(parser), path_(path), file_name_(file_name) {}
  166. bool generate() {
  167. FlatBufFile file(parser_, file_name_);
  168. grpc_go_generator::Parameters p;
  169. p.custom_method_io_type = "flatbuffers.Builder";
  170. for (int i = 0; i < file.service_count(); i++) {
  171. auto service = file.service(i);
  172. const Definition *def = parser_.services_.vec[i];
  173. p.package_name = LastNamespacePart(*(def->defined_namespace));
  174. std::string output = grpc_go_generator::GenerateServiceSource(&file, service.get(), &p);
  175. std::string filename = NamespaceDir(*def->defined_namespace) + def->name + "_grpc.go";
  176. if (!flatbuffers::SaveFile(filename.c_str(), output, false))
  177. return false;
  178. }
  179. return true;
  180. }
  181. protected:
  182. const Parser &parser_;
  183. const std::string &path_, &file_name_;
  184. };
  185. bool GenerateGoGRPC(const Parser &parser,
  186. const std::string &path,
  187. const std::string &file_name) {
  188. int nservices = 0;
  189. for (auto it = parser.services_.vec.begin();
  190. it != parser.services_.vec.end(); ++it) {
  191. if (!(*it)->generated) nservices++;
  192. }
  193. if (!nservices) return true;
  194. return GoGRPCGenerator(parser, path, file_name).generate();
  195. }
  196. bool GenerateCppGRPC(const Parser &parser,
  197. const std::string &/*path*/,
  198. const std::string &file_name) {
  199. int nservices = 0;
  200. for (auto it = parser.services_.vec.begin();
  201. it != parser.services_.vec.end(); ++it) {
  202. if (!(*it)->generated) nservices++;
  203. }
  204. if (!nservices) return true;
  205. grpc_cpp_generator::Parameters generator_parameters;
  206. // TODO(wvo): make the other parameters in this struct configurable.
  207. generator_parameters.use_system_headers = true;
  208. FlatBufFile fbfile(parser, file_name);
  209. std::string header_code =
  210. grpc_cpp_generator::GetHeaderPrologue(&fbfile, generator_parameters) +
  211. grpc_cpp_generator::GetHeaderIncludes(&fbfile, generator_parameters) +
  212. grpc_cpp_generator::GetHeaderServices(&fbfile, generator_parameters) +
  213. grpc_cpp_generator::GetHeaderEpilogue(&fbfile, generator_parameters);
  214. std::string source_code =
  215. grpc_cpp_generator::GetSourcePrologue(&fbfile, generator_parameters) +
  216. grpc_cpp_generator::GetSourceIncludes(&fbfile, generator_parameters) +
  217. grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) +
  218. grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters);
  219. return flatbuffers::SaveFile((file_name + ".grpc.fb.h").c_str(),
  220. header_code, false) &&
  221. flatbuffers::SaveFile((file_name + ".grpc.fb.cc").c_str(),
  222. source_code, false);
  223. }
  224. } // namespace flatbuffers