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$ \"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["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 |
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["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 |
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 |
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 | |