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 40template <class T> 41grpc::string as_string(T x) { 42 std::ostringstream out; 43 out << x; 44 return out.str(); 45} 46 47namespace grpc_go_generator { 48 49// Returns string with first letter to lowerCase 50grpc::string unexportName(grpc::string s) { 51 if (s.empty()) 52 return s; 53 s[0] = static_cast<char>(std::tolower(s[0])); 54 return s; 55} 56 57// Returns string with first letter to uppercase 58grpc::string exportName(grpc::string s) { 59 if (s.empty()) 60 return s; 61 s[0] = static_cast<char>(std::toupper(s[0])); 62 return s; 63} 64 65// Generates imports for the service 66void GenerateImports(grpc_generator::File *file, grpc_generator::Printer *printer, 67 std::map<grpc::string, grpc::string> vars) { 68 vars["filename"] = file->filename(); 69 printer->Print("//Generated by gRPC Go plugin\n"); 70 printer->Print("//If you make any local changes, they will be lost\n"); 71 printer->Print(vars, "//source: $filename$\n\n"); 72 printer->Print(vars, "package $Package$\n\n"); 73 if (file->additional_imports() != "") { 74 printer->Print(file->additional_imports().c_str()); 75 printer->Print("\n\n"); 76 } 77 printer->Print("import (\n"); 78 printer->Indent(); 79 printer->Print(vars, "$context$ \"golang.org/x/net/context\"\n"); 80 printer->Print(vars, "$grpc$ \"google.golang.org/grpc\"\n"); 81 printer->Outdent(); 82 printer->Print(")\n\n"); 83} 84 85// Generates Server method signature source 86void GenerateServerMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer, 87 std::map<grpc::string, grpc::string> vars) { 88 vars["Method"] = exportName(method->name()); 89 vars["Request"] = method->input_name(); 90 vars["Response"] = (vars["CustomMethodIO"] == "") ? method->output_name() : vars["CustomMethodIO"]; 91 if (method->NoStreaming()) { 92 printer->Print(vars, "$Method$($context$.Context, *$Request$) (*$Response$, error)"); 93 } else if (method->ServerOnlyStreaming()) { 94 printer->Print(vars, "$Method$(*$Request$, $Service$_$Method$Server) error"); 95 } else { 96 printer->Print(vars, "$Method$($Service$_$Method$Server) error"); 97 } 98} 99 100void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer, 101 std::map<grpc::string, grpc::string> vars) { 102 vars["Method"] = exportName(method->name()); 103 vars["Request"] = method->input_name(); 104 vars["Response"] = (vars["CustomMethodIO"] == "") ? method->output_name() : vars["CustomMethodIO"]; 105 vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"]; 106 vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler"; 107 if (method->NoStreaming()) { 108 printer->Print(vars, "func $Handler$(srv interface{}, ctx $context$.Context,\n\tdec func(interface{}) error, interceptor $grpc$.UnaryServerInterceptor) (interface{}, error) {\n"); 109 printer->Indent(); 110 printer->Print(vars, "in := new($Request$)\n"); 111 printer->Print("if err := dec(in); err != nil { return nil, err }\n"); 112 printer->Print(vars, "if interceptor == nil { return srv.($Service$Server).$Method$(ctx, in) }\n"); 113 printer->Print(vars, "info := &$grpc$.UnaryServerInfo{\n"); 114 printer->Indent(); 115 printer->Print("Server: srv,\n"); 116 printer->Print(vars, "FullMethod: \"$FullMethodName$\",\n"); 117 printer->Outdent(); 118 printer->Print("}\n\n"); 119 printer->Print(vars, "handler := func(ctx $context$.Context, req interface{}) (interface{}, error) {\n"); 120 printer->Indent(); 121 printer->Print(vars, "return srv.($Service$Server).$Method$(ctx, req.(* $Request$))\n"); 122 printer->Outdent(); 123 printer->Print("}\n"); 124 printer->Print("return interceptor(ctx, in, info, handler)\n"); 125 printer->Outdent(); 126 printer->Print("}\n\n"); 127 return; 128 } 129 vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Server"; 130 printer->Print(vars, "func $Handler$(srv interface{}, stream $grpc$.ServerStream) error {\n"); 131 printer->Indent(); 132 if (method->ServerOnlyStreaming()) { 133 printer->Print(vars, "m := new($Request$)\n"); 134 printer->Print(vars, "if err := stream.RecvMsg(m); err != nil { return err }\n"); 135 printer->Print(vars, "return srv.($Service$Server).$Method$(m, &$StreamType${stream})\n"); 136 } else { 137 printer->Print(vars, "return srv.($Service$Server).$Method$(&$StreamType${stream})\n"); 138 } 139 printer->Outdent(); 140 printer->Print("}\n\n"); 141 142 bool genSend = method->BidiStreaming() || method->ServerOnlyStreaming(); 143 bool genRecv = method->BidiStreaming() || method->ClientOnlyStreaming(); 144 bool genSendAndClose = method->ClientOnlyStreaming(); 145 146 printer->Print(vars, "type $Service$_$Method$Server interface { \n"); 147 printer->Indent(); 148 if (genSend) { 149 printer->Print(vars, "Send(* $Response$) error\n"); 150 } 151 if (genRecv) { 152 printer->Print(vars, "Recv() (* $Request$, error)\n"); 153 } 154 if (genSendAndClose) { 155 printer->Print(vars, "SendAndClose(* $Response$) error\n"); 156 } 157 printer->Print(vars, "$grpc$.ServerStream\n"); 158 printer->Outdent(); 159 printer->Print("}\n\n"); 160 161 printer->Print(vars, "type $StreamType$ struct {\n"); 162 printer->Indent(); 163 printer->Print(vars, "$grpc$.ServerStream\n"); 164 printer->Outdent(); 165 printer->Print("}\n\n"); 166 167 if (genSend) { 168 printer->Print(vars, "func (x *$StreamType$) Send(m *$Response$) error {\n"); 169 printer->Indent(); 170 printer->Print("return x.ServerStream.SendMsg(m)\n"); 171 printer->Outdent(); 172 printer->Print("}\n\n"); 173 } 174 if (genRecv) { 175 printer->Print(vars, "func (x *$StreamType$) Recv() (*$Request$, error) {\n"); 176 printer->Indent(); 177 printer->Print(vars, "m := new($Request$)\n"); 178 printer->Print("if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err }\n"); 179 printer->Print("return m, nil\n"); 180 printer->Outdent(); 181 printer->Print("}\n\n"); 182 } 183 if (genSendAndClose) { 184 printer->Print(vars, "func (x *$StreamType$) SendAndClose(m *$Response$) error {\n"); 185 printer->Indent(); 186 printer->Print("return x.ServerStream.SendMsg(m)\n"); 187 printer->Outdent(); 188 printer->Print("}\n\n"); 189 } 190 191} 192 193// Generates Client method signature source 194void GenerateClientMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer, 195 std::map<grpc::string, grpc::string> vars) { 196 vars["Method"] = exportName(method->name()); 197 vars["Request"] = ", in *" + ((vars["CustomMethodIO"] == "") ? method->input_name() : vars["CustomMethodIO"]); 198 if (method->ClientOnlyStreaming() || method->BidiStreaming()) { 199 vars["Request"] = ""; 200 } 201 vars["Response"] = "* " + method->output_name(); 202 if (method->ClientOnlyStreaming() || method->BidiStreaming() || method->ServerOnlyStreaming()) { 203 vars["Response"] = vars["Service"] + "_" + vars["Method"] + "Client" ; 204 } 205 printer->Print(vars, "$Method$(ctx $context$.Context$Request$, \n\topts... $grpc$.CallOption) ($Response$, error)"); 206} 207 208// Generates Client method source 209void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer, 210 std::map<grpc::string, grpc::string> vars) { 211 printer->Print(vars, "func (c *$ServiceUnexported$Client) "); 212 GenerateClientMethodSignature(method, printer, vars); 213 printer->Print(" {\n"); 214 printer->Indent(); 215 vars["Method"] = exportName(method->name()); 216 vars["Request"] = (vars["CustomMethodIO"] == "") ? method->input_name() : vars["CustomMethodIO"]; 217 vars["Response"] = method->output_name(); 218 vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"]; 219 if (method->NoStreaming()) { 220 printer->Print(vars, "out := new($Response$)\n"); 221 printer->Print(vars, "err := $grpc$.Invoke(ctx, \"$FullMethodName$\", in, out, c.cc, opts...)\n"); 222 printer->Print("if err != nil { return nil, err }\n"); 223 printer->Print("return out, nil\n"); 224 printer->Outdent(); 225 printer->Print("}\n\n"); 226 return; 227 } 228 vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Client"; 229 printer->Print(vars, "stream, err := $grpc$.NewClientStream(ctx, &$MethodDesc$, c.cc, \"$FullMethodName$\", opts...)\n"); 230 printer->Print("if err != nil { return nil, err }\n"); 231 232 printer->Print(vars, "x := &$StreamType${stream}\n"); 233 if (method->ServerOnlyStreaming()) { 234 printer->Print("if err := x.ClientStream.SendMsg(in); err != nil { return nil, err }\n"); 235 printer->Print("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }\n"); 236 } 237 printer->Print("return x,nil\n"); 238 printer->Outdent(); 239 printer->Print("}\n\n"); 240 241 bool genSend = method->BidiStreaming() || method->ClientOnlyStreaming(); 242 bool genRecv = method->BidiStreaming() || method->ServerOnlyStreaming(); 243 bool genCloseAndRecv = method->ClientOnlyStreaming(); 244 245 //Stream interface 246 printer->Print(vars, "type $Service$_$Method$Client interface {\n"); 247 printer->Indent(); 248 if (genSend) { 249 printer->Print(vars, "Send(*$Request$) error\n"); 250 } 251 if (genRecv) { 252 printer->Print(vars, "Recv() (*$Response$, error)\n"); 253 } 254 if (genCloseAndRecv) { 255 printer->Print(vars, "CloseAndRecv() (*$Response$, error)\n"); 256 } 257 printer->Print(vars, "$grpc$.ClientStream\n"); 258 printer->Outdent(); 259 printer->Print("}\n\n"); 260 261 //Stream Client 262 printer->Print(vars, "type $StreamType$ struct{\n"); 263 printer->Indent(); 264 printer->Print(vars, "$grpc$.ClientStream\n"); 265 printer->Outdent(); 266 printer->Print("}\n\n"); 267 268 if (genSend) { 269 printer->Print(vars, "func (x *$StreamType$) Send(m *$Request$) error {\n"); 270 printer->Indent(); 271 printer->Print("return x.ClientStream.SendMsg(m)\n"); 272 printer->Outdent(); 273 printer->Print("}\n\n"); 274 } 275 276 if (genRecv) { 277 printer->Print(vars, "func (x *$StreamType$) Recv() (*$Response$, error) {\n"); 278 printer->Indent(); 279 printer->Print(vars, "m := new($Response$)\n"); 280 printer->Print("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }\n"); 281 printer->Print("return m, nil\n"); 282 printer->Outdent(); 283 printer->Print("}\n\n"); 284 } 285 286 if (genCloseAndRecv) { 287 printer->Print(vars, "func (x *$StreamType$) CloseAndRecv() (*$Response$, error) {\n"); 288 printer->Indent(); 289 printer->Print("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }\n"); 290 printer->Print(vars, "m := new ($Response$)\n"); 291 printer->Print("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }\n"); 292 printer->Print("return m, nil\n"); 293 printer->Outdent(); 294 printer->Print("}\n\n"); 295 } 296} 297 298// Generates client API for the service 299void GenerateService(const grpc_generator::Service *service, grpc_generator::Printer* printer, 300 std::map<grpc::string, grpc::string> vars) { 301 vars["Service"] = exportName(service->name()); 302 // Client Interface 303 printer->Print(vars, "// Client API for $Service$ service\n"); 304 printer->Print(vars, "type $Service$Client interface{\n"); 305 printer->Indent(); 306 for (int i = 0; i < service->method_count(); i++) { 307 GenerateClientMethodSignature(service->method(i).get(), printer, vars); 308 printer->Print("\n"); 309 } 310 printer->Outdent(); 311 printer->Print("}\n\n"); 312 313 // Client structure 314 vars["ServiceUnexported"] = unexportName(vars["Service"]); 315 printer->Print(vars, "type $ServiceUnexported$Client struct {\n"); 316 printer->Indent(); 317 printer->Print(vars, "cc *$grpc$.ClientConn\n"); 318 printer->Outdent(); 319 printer->Print("}\n\n"); 320 321 // NewClient 322 printer->Print(vars, "func New$Service$Client(cc *$grpc$.ClientConn) $Service$Client {\n"); 323 printer->Indent(); 324 printer->Print(vars, "return &$ServiceUnexported$Client{cc}"); 325 printer->Outdent(); 326 printer->Print("\n}\n\n"); 327 328 int unary_methods = 0, streaming_methods = 0; 329 vars["ServiceDesc"] = "_" + vars["Service"] + "_serviceDesc"; 330 for (int i = 0; i < service->method_count(); i++) { 331 auto method = service->method(i); 332 if (method->NoStreaming()) { 333 vars["MethodDesc"] = vars["ServiceDesc"] + ".Method[" + as_string(unary_methods) + "]"; 334 unary_methods++; 335 } else { 336 vars["MethodDesc"] = vars["ServiceDesc"] + ".Streams[" + as_string(streaming_methods) + "]"; 337 streaming_methods++; 338 } 339 GenerateClientMethod(method.get(), printer, vars); 340 } 341 342 //Server Interface 343 printer->Print(vars, "// Server API for $Service$ service\n"); 344 printer->Print(vars, "type $Service$Server interface {\n"); 345 printer->Indent(); 346 for (int i = 0; i < service->method_count(); i++) { 347 GenerateServerMethodSignature(service->method(i).get(), printer, vars); 348 printer->Print("\n"); 349 } 350 printer->Outdent(); 351 printer->Print("}\n\n"); 352 353 // Server registration. 354 printer->Print(vars, "func Register$Service$Server(s *$grpc$.Server, srv $Service$Server) {\n"); 355 printer->Indent(); 356 printer->Print(vars, "s.RegisterService(&$ServiceDesc$, srv)\n"); 357 printer->Outdent(); 358 printer->Print("}\n\n"); 359 360 for (int i = 0; i < service->method_count(); i++) { 361 GenerateServerMethod(service->method(i).get(), printer, vars); 362 printer->Print("\n"); 363 } 364 365 366 //Service Descriptor 367 printer->Print(vars, "var $ServiceDesc$ = $grpc$.ServiceDesc{\n"); 368 printer->Indent(); 369 printer->Print(vars, "ServiceName: \"$Package$.$Service$\",\n"); 370 printer->Print(vars, "HandlerType: (*$Service$Server)(nil),\n"); 371 printer->Print(vars, "Methods: []$grpc$.MethodDesc{\n"); 372 printer->Indent(); 373 for (int i = 0; i < service->method_count(); i++) { 374 auto method = service->method(i); 375 vars["Method"] = method->name(); 376 vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler"; 377 if (method->NoStreaming()) { 378 printer->Print("{\n"); 379 printer->Indent(); 380 printer->Print(vars, "MethodName: \"$Method$\",\n"); 381 printer->Print(vars, "Handler: $Handler$, \n"); 382 printer->Outdent(); 383 printer->Print("},\n"); 384 } 385 } 386 printer->Outdent(); 387 printer->Print("},\n"); 388 printer->Print(vars, "Streams: []$grpc$.StreamDesc{\n"); 389 printer->Indent(); 390 for (int i = 0; i < service->method_count(); i++) { 391 auto method = service->method(i); 392 vars["Method"] = method->name(); 393 vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler"; 394 if (!method->NoStreaming()) { 395 printer->Print("{\n"); 396 printer->Indent(); 397 printer->Print(vars, "StreamName: \"$Method$\",\n"); 398 printer->Print(vars, "Handler: $Handler$, \n"); 399 if (method->ClientOnlyStreaming()) { 400 printer->Print("ClientStreams: true,\n"); 401 } else if (method->ServerOnlyStreaming()) { 402 printer->Print("ServerStreams: true,\n"); 403 } else { 404 printer->Print("ServerStreams: true,\n"); 405 printer->Print("ClientStreams: true,\n"); 406 } 407 printer->Outdent(); 408 printer->Print("},\n"); 409 } 410 } 411 printer->Outdent(); 412 printer->Print("},\n"); 413 printer->Outdent(); 414 printer->Print("}\n\n"); 415 416} 417 418 419// Returns source for the service 420grpc::string GenerateServiceSource(grpc_generator::File *file, 421 const grpc_generator::Service *service, 422 grpc_go_generator::Parameters *parameters) { 423 grpc::string out; 424 auto p = file->CreatePrinter(&out); 425 auto printer = p.get(); 426 std::map<grpc::string, grpc::string> vars; 427 vars["Package"] = parameters->package_name; 428 vars["grpc"] = "grpc"; 429 vars["context"] = "context"; 430 GenerateImports(file, printer, vars); 431 if (parameters->custom_method_io_type != "") { 432 vars["CustomMethodIO"] = parameters->custom_method_io_type; 433 } 434 GenerateService(service, printer, vars); 435 return out; 436} 437}// Namespace grpc_go_generator 438