1 /* 2 * 3 * Copyright 2015, Google Inc. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following disclaimer 14 * in the documentation AN/or other materials provided with the 15 * distribution. 16 * * Neither the name of Google Inc. nor the names of its 17 * contributors may be used to endorse or promote products derived from 18 * this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 */ 33 34 #include <map> 35 #include <cctype> 36 #include <sstream> 37 38 #include "src/compiler/go_generator.h" 39 40 template <class T> 41 grpc::string as_string(T x) { 42 std::ostringstream out; 43 out << x; 44 return out.str(); 45 } 46 47 inline bool ClientOnlyStreaming(const grpc_generator::Method *method) { 48 return method->ClientStreaming() && !method->ServerStreaming(); 49 } 50 51 inline bool ServerOnlyStreaming(const grpc_generator::Method *method) { 52 return !method->ClientStreaming() && method->ServerStreaming(); 53 } 54 55 namespace grpc_go_generator { 56 57 // Returns string with first letter to lowerCase 58 grpc::string unexportName(grpc::string s) { 59 if (s.empty()) 60 return s; 61 s[0] = static_cast<char>(std::tolower(s[0])); 62 return s; 63 } 64 65 // Returns string with first letter to uppercase 66 grpc::string exportName(grpc::string s) { 67 if (s.empty()) 68 return s; 69 s[0] = static_cast<char>(std::toupper(s[0])); 70 return s; 71 } 72 73 // Generates imports for the service 74 void GenerateImports(grpc_generator::File *file, grpc_generator::Printer *printer, 75 std::map<grpc::string, grpc::string> vars) { 76 vars["filename"] = file->filename(); 77 printer->Print("//Generated by gRPC Go plugin\n"); 78 printer->Print("//If you make any local changes, they will be lost\n"); 79 printer->Print(vars, "//source: $filename$\n\n"); 80 printer->Print(vars, "package $Package$\n\n"); 81 if (file->additional_headers() != "") { 82 printer->Print(file->additional_headers().c_str()); 83 printer->Print("\n\n"); 84 } 85 printer->Print("import (\n"); 86 printer->Indent(); 87 printer->Print(vars, "$context$ \"golang.org/x/net/context\"\n"); 88 printer->Print(vars, "$grpc$ \"google.golang.org/grpc\"\n"); 89 printer->Outdent(); 90 printer->Print(")\n\n"); 91 } 92 93 // Generates Server method signature source 94 void GenerateServerMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer, 95 std::map<grpc::string, grpc::string> vars) { 96 vars["Method"] = exportName(method->name()); 97 vars["Request"] = method->get_input_type_name(); 98 vars["Response"] = (vars["CustomMethodIO"] == "") ? method->get_output_type_name() : vars["CustomMethodIO"]; 99 if (method->NoStreaming()) { 100 printer->Print(vars, "$Method$($context$.Context, *$Request$) (*$Response$, error)"); 101 } else if (ServerOnlyStreaming(method)) { 102 printer->Print(vars, "$Method$(*$Request$, $Service$_$Method$Server) error"); 103 } else { 104 printer->Print(vars, "$Method$($Service$_$Method$Server) error"); 105 } 106 } 107 108 void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer, 109 std::map<grpc::string, grpc::string> vars) { 110 vars["Method"] = exportName(method->name()); 111 vars["Request"] = method->get_input_type_name(); 112 vars["Response"] = (vars["CustomMethodIO"] == "") ? method->get_output_type_name() : vars["CustomMethodIO"]; 113 vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"]; 114 vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler"; 115 if (method->NoStreaming()) { 116 printer->Print(vars, "func $Handler$(srv interface{}, ctx $context$.Context,\n\tdec func(interface{}) error, interceptor $grpc$.UnaryServerInterceptor) (interface{}, error) {\n"); 117 printer->Indent(); 118 printer->Print(vars, "in := new($Request$)\n"); 119 printer->Print("if err := dec(in); err != nil { return nil, err }\n"); 120 printer->Print(vars, "if interceptor == nil { return srv.($Service$Server).$Method$(ctx, in) }\n"); 121 printer->Print(vars, "info := &$grpc$.UnaryServerInfo{\n"); 122 printer->Indent(); 123 printer->Print("Server: srv,\n"); 124 printer->Print(vars, "FullMethod: \"$FullMethodName$\",\n"); 125 printer->Outdent(); 126 printer->Print("}\n\n"); 127 printer->Print(vars, "handler := func(ctx $context$.Context, req interface{}) (interface{}, error) {\n"); 128 printer->Indent(); 129 printer->Print(vars, "return srv.($Service$Server).$Method$(ctx, req.(* $Request$))\n"); 130 printer->Outdent(); 131 printer->Print("}\n"); 132 printer->Print("return interceptor(ctx, in, info, handler)\n"); 133 printer->Outdent(); 134 printer->Print("}\n\n"); 135 return; 136 } 137 vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Server"; 138 printer->Print(vars, "func $Handler$(srv interface{}, stream $grpc$.ServerStream) error {\n"); 139 printer->Indent(); 140 if (ServerOnlyStreaming(method)) { 141 printer->Print(vars, "m := new($Request$)\n"); 142 printer->Print(vars, "if err := stream.RecvMsg(m); err != nil { return err }\n"); 143 printer->Print(vars, "return srv.($Service$Server).$Method$(m, &$StreamType${stream})\n"); 144 } else { 145 printer->Print(vars, "return srv.($Service$Server).$Method$(&$StreamType${stream})\n"); 146 } 147 printer->Outdent(); 148 printer->Print("}\n\n"); 149 150 bool genSend = method->BidiStreaming() || ServerOnlyStreaming(method); 151 bool genRecv = method->BidiStreaming() || ClientOnlyStreaming(method); 152 bool genSendAndClose = ClientOnlyStreaming(method); 153 154 printer->Print(vars, "type $Service$_$Method$Server interface { \n"); 155 printer->Indent(); 156 if (genSend) { 157 printer->Print(vars, "Send(* $Response$) error\n"); 158 } 159 if (genRecv) { 160 printer->Print(vars, "Recv() (* $Request$, error)\n"); 161 } 162 if (genSendAndClose) { 163 printer->Print(vars, "SendAndClose(* $Response$) error\n"); 164 } 165 printer->Print(vars, "$grpc$.ServerStream\n"); 166 printer->Outdent(); 167 printer->Print("}\n\n"); 168 169 printer->Print(vars, "type $StreamType$ struct {\n"); 170 printer->Indent(); 171 printer->Print(vars, "$grpc$.ServerStream\n"); 172 printer->Outdent(); 173 printer->Print("}\n\n"); 174 175 if (genSend) { 176 printer->Print(vars, "func (x *$StreamType$) Send(m *$Response$) error {\n"); 177 printer->Indent(); 178 printer->Print("return x.ServerStream.SendMsg(m)\n"); 179 printer->Outdent(); 180 printer->Print("}\n\n"); 181 } 182 if (genRecv) { 183 printer->Print(vars, "func (x *$StreamType$) Recv() (*$Request$, error) {\n"); 184 printer->Indent(); 185 printer->Print(vars, "m := new($Request$)\n"); 186 printer->Print("if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err }\n"); 187 printer->Print("return m, nil\n"); 188 printer->Outdent(); 189 printer->Print("}\n\n"); 190 } 191 if (genSendAndClose) { 192 printer->Print(vars, "func (x *$StreamType$) SendAndClose(m *$Response$) error {\n"); 193 printer->Indent(); 194 printer->Print("return x.ServerStream.SendMsg(m)\n"); 195 printer->Outdent(); 196 printer->Print("}\n\n"); 197 } 198 199 } 200 201 // Generates Client method signature source 202 void GenerateClientMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer, 203 std::map<grpc::string, grpc::string> vars) { 204 vars["Method"] = exportName(method->name()); 205 vars["Request"] = ", in *" + ((vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"]); 206 if (ClientOnlyStreaming(method) || method->BidiStreaming()) { 207 vars["Request"] = ""; 208 } 209 vars["Response"] = "* " + method->get_output_type_name(); 210 if (ClientOnlyStreaming(method) || method->BidiStreaming() || ServerOnlyStreaming(method)) { 211 vars["Response"] = vars["Service"] + "_" + vars["Method"] + "Client" ; 212 } 213 printer->Print(vars, "$Method$(ctx $context$.Context$Request$, \n\topts... $grpc$.CallOption) ($Response$, error)"); 214 } 215 216 // Generates Client method source 217 void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer, 218 std::map<grpc::string, grpc::string> vars) { 219 printer->Print(vars, "func (c *$ServiceUnexported$Client) "); 220 GenerateClientMethodSignature(method, printer, vars); 221 printer->Print(" {\n"); 222 printer->Indent(); 223 vars["Method"] = exportName(method->name()); 224 vars["Request"] = (vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"]; 225 vars["Response"] = method->get_output_type_name(); 226 vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"]; 227 if (method->NoStreaming()) { 228 printer->Print(vars, "out := new($Response$)\n"); 229 printer->Print(vars, "err := $grpc$.Invoke(ctx, \"$FullMethodName$\", in, out, c.cc, opts...)\n"); 230 printer->Print("if err != nil { return nil, err }\n"); 231 printer->Print("return out, nil\n"); 232 printer->Outdent(); 233 printer->Print("}\n\n"); 234 return; 235 } 236 vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Client"; 237 printer->Print(vars, "stream, err := $grpc$.NewClientStream(ctx, &$MethodDesc$, c.cc, \"$FullMethodName$\", opts...)\n"); 238 printer->Print("if err != nil { return nil, err }\n"); 239 240 printer->Print(vars, "x := &$StreamType${stream}\n"); 241 if (ServerOnlyStreaming(method)) { 242 printer->Print("if err := x.ClientStream.SendMsg(in); err != nil { return nil, err }\n"); 243 printer->Print("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }\n"); 244 } 245 printer->Print("return x,nil\n"); 246 printer->Outdent(); 247 printer->Print("}\n\n"); 248 249 bool genSend = method->BidiStreaming() || ClientOnlyStreaming(method); 250 bool genRecv = method->BidiStreaming() || ServerOnlyStreaming(method); 251 bool genCloseAndRecv = ClientOnlyStreaming(method); 252 253 //Stream interface 254 printer->Print(vars, "type $Service$_$Method$Client interface {\n"); 255 printer->Indent(); 256 if (genSend) { 257 printer->Print(vars, "Send(*$Request$) error\n"); 258 } 259 if (genRecv) { 260 printer->Print(vars, "Recv() (*$Response$, error)\n"); 261 } 262 if (genCloseAndRecv) { 263 printer->Print(vars, "CloseAndRecv() (*$Response$, error)\n"); 264 } 265 printer->Print(vars, "$grpc$.ClientStream\n"); 266 printer->Outdent(); 267 printer->Print("}\n\n"); 268 269 //Stream Client 270 printer->Print(vars, "type $StreamType$ struct{\n"); 271 printer->Indent(); 272 printer->Print(vars, "$grpc$.ClientStream\n"); 273 printer->Outdent(); 274 printer->Print("}\n\n"); 275 276 if (genSend) { 277 printer->Print(vars, "func (x *$StreamType$) Send(m *$Request$) error {\n"); 278 printer->Indent(); 279 printer->Print("return x.ClientStream.SendMsg(m)\n"); 280 printer->Outdent(); 281 printer->Print("}\n\n"); 282 } 283 284 if (genRecv) { 285 printer->Print(vars, "func (x *$StreamType$) Recv() (*$Response$, error) {\n"); 286 printer->Indent(); 287 printer->Print(vars, "m := new($Response$)\n"); 288 printer->Print("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }\n"); 289 printer->Print("return m, nil\n"); 290 printer->Outdent(); 291 printer->Print("}\n\n"); 292 } 293 294 if (genCloseAndRecv) { 295 printer->Print(vars, "func (x *$StreamType$) CloseAndRecv() (*$Response$, error) {\n"); 296 printer->Indent(); 297 printer->Print("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }\n"); 298 printer->Print(vars, "m := new ($Response$)\n"); 299 printer->Print("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }\n"); 300 printer->Print("return m, nil\n"); 301 printer->Outdent(); 302 printer->Print("}\n\n"); 303 } 304 } 305 306 // Generates client API for the service 307 void GenerateService(const grpc_generator::Service *service, grpc_generator::Printer* printer, 308 std::map<grpc::string, grpc::string> vars) { 309 vars["Service"] = exportName(service->name()); 310 // Client Interface 311 printer->Print(vars, "// Client API for $Service$ service\n"); 312 printer->Print(vars, "type $Service$Client interface{\n"); 313 printer->Indent(); 314 for (int i = 0; i < service->method_count(); i++) { 315 GenerateClientMethodSignature(service->method(i).get(), printer, vars); 316 printer->Print("\n"); 317 } 318 printer->Outdent(); 319 printer->Print("}\n\n"); 320 321 // Client structure 322 vars["ServiceUnexported"] = unexportName(vars["Service"]); 323 printer->Print(vars, "type $ServiceUnexported$Client struct {\n"); 324 printer->Indent(); 325 printer->Print(vars, "cc *$grpc$.ClientConn\n"); 326 printer->Outdent(); 327 printer->Print("}\n\n"); 328 329 // NewClient 330 printer->Print(vars, "func New$Service$Client(cc *$grpc$.ClientConn) $Service$Client {\n"); 331 printer->Indent(); 332 printer->Print(vars, "return &$ServiceUnexported$Client{cc}"); 333 printer->Outdent(); 334 printer->Print("\n}\n\n"); 335 336 int unary_methods = 0, streaming_methods = 0; 337 vars["ServiceDesc"] = "_" + vars["Service"] + "_serviceDesc"; 338 for (int i = 0; i < service->method_count(); i++) { 339 auto method = service->method(i); 340 if (method->NoStreaming()) { 341 vars["MethodDesc"] = vars["ServiceDesc"] + ".Method[" + as_string(unary_methods) + "]"; 342 unary_methods++; 343 } else { 344 vars["MethodDesc"] = vars["ServiceDesc"] + ".Streams[" + as_string(streaming_methods) + "]"; 345 streaming_methods++; 346 } 347 GenerateClientMethod(method.get(), printer, vars); 348 } 349 350 //Server Interface 351 printer->Print(vars, "// Server API for $Service$ service\n"); 352 printer->Print(vars, "type $Service$Server interface {\n"); 353 printer->Indent(); 354 for (int i = 0; i < service->method_count(); i++) { 355 GenerateServerMethodSignature(service->method(i).get(), printer, vars); 356 printer->Print("\n"); 357 } 358 printer->Outdent(); 359 printer->Print("}\n\n"); 360 361 // Server registration. 362 printer->Print(vars, "func Register$Service$Server(s *$grpc$.Server, srv $Service$Server) {\n"); 363 printer->Indent(); 364 printer->Print(vars, "s.RegisterService(&$ServiceDesc$, srv)\n"); 365 printer->Outdent(); 366 printer->Print("}\n\n"); 367 368 for (int i = 0; i < service->method_count(); i++) { 369 GenerateServerMethod(service->method(i).get(), printer, vars); 370 printer->Print("\n"); 371 } 372 373 374 //Service Descriptor 375 printer->Print(vars, "var $ServiceDesc$ = $grpc$.ServiceDesc{\n"); 376 printer->Indent(); 377 printer->Print(vars, "ServiceName: \"$Package$.$Service$\",\n"); 378 printer->Print(vars, "HandlerType: (*$Service$Server)(nil),\n"); 379 printer->Print(vars, "Methods: []$grpc$.MethodDesc{\n"); 380 printer->Indent(); 381 for (int i = 0; i < service->method_count(); i++) { 382 auto method = service->method(i); 383 vars["Method"] = method->name(); 384 vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler"; 385 if (method->NoStreaming()) { 386 printer->Print("{\n"); 387 printer->Indent(); 388 printer->Print(vars, "MethodName: \"$Method$\",\n"); 389 printer->Print(vars, "Handler: $Handler$, \n"); 390 printer->Outdent(); 391 printer->Print("},\n"); 392 } 393 } 394 printer->Outdent(); 395 printer->Print("},\n"); 396 printer->Print(vars, "Streams: []$grpc$.StreamDesc{\n"); 397 printer->Indent(); 398 for (int i = 0; i < service->method_count(); i++) { 399 auto method = service->method(i); 400 vars["Method"] = method->name(); 401 vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler"; 402 if (!method->NoStreaming()) { 403 printer->Print("{\n"); 404 printer->Indent(); 405 printer->Print(vars, "StreamName: \"$Method$\",\n"); 406 printer->Print(vars, "Handler: $Handler$, \n"); 407 if (ClientOnlyStreaming(method.get())) { 408 printer->Print("ClientStreams: true,\n"); 409 } else if (ServerOnlyStreaming(method.get())) { 410 printer->Print("ServerStreams: true,\n"); 411 } else { 412 printer->Print("ServerStreams: true,\n"); 413 printer->Print("ClientStreams: true,\n"); 414 } 415 printer->Outdent(); 416 printer->Print("},\n"); 417 } 418 } 419 printer->Outdent(); 420 printer->Print("},\n"); 421 printer->Outdent(); 422 printer->Print("}\n\n"); 423 424 } 425 426 427 // Returns source for the service 428 grpc::string GenerateServiceSource(grpc_generator::File *file, 429 const grpc_generator::Service *service, 430 grpc_go_generator::Parameters *parameters) { 431 grpc::string out; 432 auto p = file->CreatePrinter(&out); 433 auto printer = p.get(); 434 std::map<grpc::string, grpc::string> vars; 435 vars["Package"] = parameters->package_name; 436 vars["grpc"] = "grpc"; 437 vars["context"] = "context"; 438 GenerateImports(file, printer, vars); 439 if (parameters->custom_method_io_type != "") { 440 vars["CustomMethodIO"] = parameters->custom_method_io_type; 441 } 442 GenerateService(service, printer, vars); 443 return out; 444 } 445 }// Namespace grpc_go_generator 446