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