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 
47 namespace grpc_go_generator {
48 
49 // Returns string with first letter to lowerCase
unexportName(grpc::string s)50 grpc::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
exportName(grpc::string s)58 grpc::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
GenerateImports(grpc_generator::File * file,grpc_generator::Printer * printer,std::map<grpc::string,grpc::string> vars)66 void 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
GenerateServerMethodSignature(const grpc_generator::Method * method,grpc_generator::Printer * printer,std::map<grpc::string,grpc::string> vars)86 void 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 
GenerateServerMethod(const grpc_generator::Method * method,grpc_generator::Printer * printer,std::map<grpc::string,grpc::string> vars)100 void 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
GenerateClientMethodSignature(const grpc_generator::Method * method,grpc_generator::Printer * printer,std::map<grpc::string,grpc::string> vars)194 void 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
GenerateClientMethod(const grpc_generator::Method * method,grpc_generator::Printer * printer,std::map<grpc::string,grpc::string> vars)209 void 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
GenerateService(const grpc_generator::Service * service,grpc_generator::Printer * printer,std::map<grpc::string,grpc::string> vars)299 void 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
GenerateServiceSource(grpc_generator::File * file,const grpc_generator::Service * service,grpc_go_generator::Parameters * parameters)420 grpc::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