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>
as_string(T x)41 grpc::string as_string(T x) {
42 	std::ostringstream out;
43 	out << x;
44 	return out.str();
45 }
46 
ClientOnlyStreaming(const grpc_generator::Method * method)47 inline bool ClientOnlyStreaming(const grpc_generator::Method *method) {
48   return method->ClientStreaming() && !method->ServerStreaming();
49 }
50 
ServerOnlyStreaming(const grpc_generator::Method * method)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
unexportName(grpc::string s)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
exportName(grpc::string s)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
GenerateImports(grpc_generator::File * file,grpc_generator::Printer * printer,std::map<grpc::string,grpc::string> vars)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$ \"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
GenerateServerMethodSignature(const grpc_generator::Method * method,grpc_generator::Printer * printer,std::map<grpc::string,grpc::string> vars)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 
GenerateServerMethod(const grpc_generator::Method * method,grpc_generator::Printer * printer,std::map<grpc::string,grpc::string> vars)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["ServicePrefix"] + "." + 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
GenerateClientMethodSignature(const grpc_generator::Method * method,grpc_generator::Printer * printer,std::map<grpc::string,grpc::string> vars)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
GenerateClientMethod(const grpc_generator::Method * method,grpc_generator::Printer * printer,std::map<grpc::string,grpc::string> vars)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["ServicePrefix"] + "." + 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
GenerateService(const grpc_generator::Service * service,grpc_generator::Printer * printer,std::map<grpc::string,grpc::string> vars)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: \"$ServicePrefix$.$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
GenerateServiceSource(grpc_generator::File * file,const grpc_generator::Service * service,grpc_go_generator::Parameters * parameters)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["ServicePrefix"] = parameters->service_prefix;
437 	vars["grpc"] = "grpc";
438 	vars["context"] = "context";
439 	GenerateImports(file, printer, vars);
440 	if (parameters->custom_method_io_type != "") {
441 		vars["CustomMethodIO"] = parameters->custom_method_io_type;
442 	}
443 	GenerateService(service, printer, vars);
444 	return out;
445 }
446 }// Namespace grpc_go_generator
447