blob: fe9731d93cd25fb318cd78613326ac116bfc04c7 [file] [log] [blame]
Austin Schuh272c6132020-11-14 16:37:52 -08001/*
2 * Copyright 2020 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * NOTE: The following implementation is a translation for the Swift-grpc
19 * generator since flatbuffers doesnt allow plugins for now. if an issue arises
20 * please open an issue in the flatbuffers repository. This file should always
21 * be maintained according to the Swift-grpc repository
22 */
23
24#include <map>
25#include <sstream>
26
27#include "flatbuffers/util.h"
28#include "src/compiler/schema_interface.h"
29#include "src/compiler/ts_generator.h"
30
31namespace grpc_ts_generator {
32
33// MARK: - Shared code
34
35void GenerateImports(grpc_generator::Printer *printer,
36 std::map<grpc::string, grpc::string> *dictonary,
37 const bool grpc_var_import) {
38 auto vars = *dictonary;
39 printer->Print(
40 "// Generated GRPC code for FlatBuffers TS *** DO NOT EDIT ***\n");
41 printer->Print("import { flatbuffers } from 'flatbuffers';\n");
42 printer->Print(vars,
43 "import * as $FBSFile$ from './$Filename$_generated';\n");
44 printer->Print("\n");
45 if (grpc_var_import)
46 printer->Print("var grpc = require('grpc');\n");
47 else
48 printer->Print("import * as grpc from 'grpc';\n");
49 printer->Print("\n");
50}
51
52// MARK: - Generate Main GRPC Code
53
54void GetStreamType(grpc_generator::Printer *printer,
55 const grpc_generator::Method *method,
56 std::map<grpc::string, grpc::string> *dictonary) {
57 auto vars = *dictonary;
58 auto client_streaming = method->ClientStreaming() || method->BidiStreaming();
59 auto server_streaming = method->ServerStreaming() || method->BidiStreaming();
60 vars["ClientStreaming"] = client_streaming ? "true" : "false";
61 vars["ServerStreaming"] = server_streaming ? "true" : "false";
62 printer->Print(vars, "requestStream: $ClientStreaming$,\n");
63 printer->Print(vars, "responseStream: $ServerStreaming$,\n");
64}
65
66void GenerateSerializeMethod(grpc_generator::Printer *printer,
67 std::map<grpc::string, grpc::string> *dictonary) {
68 auto vars = *dictonary;
69 printer->Print(vars, "function serialize_$Type$(buffer_args) {\n");
70 printer->Indent();
71 printer->Print(vars, "if (!(buffer_args instanceof $FBSFile$.$Type$)) {\n");
72 printer->Indent();
73 printer->Print(
74 vars, "throw new Error('Expected argument of type $FBSFile$.$Type$');\n");
75 printer->Outdent();
76 printer->Print("}\n");
77 printer->Print(vars, "return buffer_args.serialize();\n");
78 printer->Outdent();
79 printer->Print("}\n\n");
80}
81
82void GenerateDeserializeMethod(
83 grpc_generator::Printer *printer,
84 std::map<grpc::string, grpc::string> *dictonary) {
85 auto vars = *dictonary;
86 printer->Print(vars, "function deserialize_$Type$(buffer) {\n");
87 printer->Indent();
88 printer->Print(vars,
89 "return $FBSFile$.$Type$.getRootAs$Type$(new "
90 "flatbuffers.ByteBuffer(buffer))\n");
91 printer->Outdent();
92 printer->Print("}\n\n");
93}
94
95void GenerateMethods(const grpc_generator::Service *service,
96 grpc_generator::Printer *printer,
97 std::map<grpc::string, grpc::string> *dictonary) {
98 auto vars = *dictonary;
99
100 std::set<grpc::string> generated_functions;
101
102 for (auto it = 0; it < service->method_count(); it++) {
103 auto method = service->method(it);
104 auto output = method->get_output_type_name();
105 auto input = method->get_input_type_name();
106
107 if (generated_functions.find(output) == generated_functions.end()) {
108 generated_functions.insert(output);
109 vars["Type"] = output;
110 GenerateSerializeMethod(printer, &vars);
111 GenerateDeserializeMethod(printer, &vars);
112 }
113 printer->Print("\n");
114 if (generated_functions.find(input) == generated_functions.end()) {
115 generated_functions.insert(input);
116 vars["Type"] = input;
117 GenerateSerializeMethod(printer, &vars);
118 GenerateDeserializeMethod(printer, &vars);
119 }
120 }
121}
122
123void GenerateService(const grpc_generator::Service *service,
124 grpc_generator::Printer *printer,
125 std::map<grpc::string, grpc::string> *dictonary) {
126 auto vars = *dictonary;
127 vars["NAME"] = service->name() + "Service";
128
129 printer->Print(vars, "var $NAME$ = exports.$NAME$ = {\n");
130 printer->Indent();
131 for (auto it = 0; it < service->method_count(); it++) {
132 auto method = service->method(it);
133 vars["MethodName"] = method->name();
134 vars["Output"] = method->get_output_type_name();
135 vars["Input"] = method->get_input_type_name();
136 printer->Print(vars, "$MethodName$: {\n");
137 printer->Indent();
138 printer->Print(vars, "path: '/$PATH$$ServiceName$/$MethodName$',\n");
139 GetStreamType(printer, &*method, &vars);
140 printer->Print(vars, "requestType: flatbuffers.ByteBuffer,\n");
141 printer->Print(vars, "responseType: $FBSFile$.$Output$,\n");
142 printer->Print(vars, "requestSerialize: serialize_$Input$,\n");
143 printer->Print(vars, "requestDeserialize: deserialize_$Input$,\n");
144 printer->Print(vars, "responseSerialize: serialize_$Output$,\n");
145 printer->Print(vars, "responseDeserialize: deserialize_$Output$,\n");
146 printer->Outdent();
147 printer->Print("},\n");
148 }
149 printer->Outdent();
150 printer->Print("};\n");
151 printer->Print(vars,
152 "exports.$ServiceName$Client = "
153 "grpc.makeGenericClientConstructor($NAME$);");
154}
155
156grpc::string Generate(grpc_generator::File *file,
157 const grpc_generator::Service *service,
158 const grpc::string &filename) {
159 grpc::string output;
160 std::map<grpc::string, grpc::string> vars;
161
162 vars["PATH"] = file->package();
163
164 if (!file->package().empty()) { vars["PATH"].append("."); }
165
166 vars["ServiceName"] = service->name();
167 vars["FBSFile"] = service->name() + "_fbs";
168 vars["Filename"] = filename;
169 auto printer = file->CreatePrinter(&output);
170
171 GenerateImports(&*printer, &vars, true);
172 GenerateMethods(service, &*printer, &vars);
173 GenerateService(service, &*printer, &vars);
174 return output;
175}
176
177// MARK: - Generate Interface
178
179void FillInterface(grpc_generator::Printer *printer,
180 std::map<grpc::string, grpc::string> *dictonary) {
181 auto vars = *dictonary;
182 printer->Print(
183 vars,
184 "interface I$ServiceName$Service_I$MethodName$ extends "
185 "grpc.MethodDefinition<$FBSFile$.$INPUT$, $FBSFile$.$OUTPUT$> {\n");
186 printer->Indent();
187 printer->Print(vars, "path: string; // /$PATH$$ServiceName$/$MethodName$\n");
188 printer->Print(vars, "requestStream: boolean; // $ClientStreaming$\n");
189 printer->Print(vars, "responseStream: boolean; // $ServerStreaming$\n");
190 printer->Print(vars,
191 "requestSerialize: grpc.serialize<$FBSFile$.$INPUT$>;\n");
192 printer->Print(vars,
193 "requestDeserialize: grpc.deserialize<$FBSFile$.$INPUT$>;\n");
194 printer->Print(vars,
195 "responseSerialize: grpc.serialize<$FBSFile$.$OUTPUT$>;\n");
196 printer->Print(
197 vars, "responseDeserialize: grpc.deserialize<$FBSFile$.$OUTPUT$>;\n");
198 printer->Outdent();
199 printer->Print("}\n");
200}
201
202void GenerateInterfaces(const grpc_generator::Service *service,
203 grpc_generator::Printer *printer,
204 std::map<grpc::string, grpc::string> *dictonary) {
205 auto vars = *dictonary;
206 for (auto it = 0; it < service->method_count(); it++) {
207 auto method = service->method(it);
208 auto client_streaming =
209 method->ClientStreaming() || method->BidiStreaming();
210 auto server_streaming =
211 method->ServerStreaming() || method->BidiStreaming();
212 vars["ClientStreaming"] = client_streaming ? "true" : "false";
213 vars["ServerStreaming"] = server_streaming ? "true" : "false";
214 vars["MethodName"] = method->name();
215 vars["INPUT"] = method->get_input_type_name();
216 vars["OUTPUT"] = method->get_output_type_name();
217 FillInterface(printer, &vars);
218 printer->Print("\n");
219 }
220}
221
222void GenerateExportedInterface(
223 const grpc_generator::Service *service, grpc_generator::Printer *printer,
224 std::map<grpc::string, grpc::string> *dictonary) {
225 auto vars = *dictonary;
226 printer->Print(vars, "export interface I$ServiceName$Server {\n");
227 printer->Indent();
228 for (auto it = 0; it < service->method_count(); it++) {
229 auto method = service->method(it);
230 vars["Name"] = method->name();
231 vars["INPUT"] = method->get_input_type_name();
232 vars["OUTPUT"] = method->get_output_type_name();
233 if (method->BidiStreaming()) {
234 printer->Print(vars,
235 "$Name$: grpc.handleBidiStreamingCall<$FBSFile$.$INPUT$, "
236 "$FBSFile$.$OUTPUT$>;\n");
237 continue;
238 }
239 if (method->NoStreaming()) {
240 printer->Print(vars,
241 "$Name$: grpc.handleUnaryCall<$FBSFile$.$INPUT$, "
242 "$FBSFile$.$OUTPUT$>;\n");
243 continue;
244 }
245 if (method->ClientStreaming()) {
246 printer->Print(
247 vars,
248 "$Name$: grpc.handleClientStreamingCall<$FBSFile$.$INPUT$, "
249 "$FBSFile$.$OUTPUT$>;\n");
250 continue;
251 }
252 if (method->ServerStreaming()) {
253 printer->Print(
254 vars,
255 "$Name$: grpc.handleServerStreamingCall<$FBSFile$.$INPUT$, "
256 "$FBSFile$.$OUTPUT$>;\n");
257 continue;
258 }
259 }
260 printer->Outdent();
261 printer->Print("}\n");
262}
263
264void GenerateMainInterface(const grpc_generator::Service *service,
265 grpc_generator::Printer *printer,
266 std::map<grpc::string, grpc::string> *dictonary) {
267 auto vars = *dictonary;
268 printer->Print(
269 vars,
270 "interface I$ServiceName$Service extends "
271 "grpc.ServiceDefinition<grpc.UntypedServiceImplementation> {\n");
272 printer->Indent();
273 for (auto it = 0; it < service->method_count(); it++) {
274 auto method = service->method(it);
275 vars["MethodName"] = method->name();
276 printer->Print(vars,
277 "$MethodName$: I$ServiceName$Service_I$MethodName$;\n");
278 }
279 printer->Outdent();
280 printer->Print("}\n");
281 GenerateInterfaces(service, printer, &vars);
282 printer->Print("\n");
283 printer->Print(vars,
284 "export const $ServiceName$Service: I$ServiceName$Service;\n");
285 printer->Print("\n");
286 GenerateExportedInterface(service, printer, &vars);
287}
288
289grpc::string GenerateMetaData() { return "metadata: grpc.Metadata"; }
290
291grpc::string GenerateOptions() { return "options: Partial<grpc.CallOptions>"; }
292
293void GenerateUnaryClientInterface(
294 grpc_generator::Printer *printer,
295 std::map<grpc::string, grpc::string> *dictonary) {
296 auto vars = *dictonary;
297 grpc::string main = "$ISPUBLIC$$MethodName$(request: $FBSFile$.$INPUT$, ";
298 grpc::string callback =
299 "callback: (error: grpc.ServiceError | null, response: "
300 "$FBSFile$.$OUTPUT$) => void): grpc.ClientUnaryCall;\n";
301 auto meta_data = GenerateMetaData() + ", ";
302 auto options = GenerateOptions() + ", ";
303 printer->Print(vars, (main + callback).c_str());
304 printer->Print(vars, (main + meta_data + callback).c_str());
305 printer->Print(vars, (main + meta_data + options + callback).c_str());
306}
307
308void GenerateClientWriteStreamInterface(
309 grpc_generator::Printer *printer,
310 std::map<grpc::string, grpc::string> *dictonary) {
311 auto vars = *dictonary;
312 grpc::string main = "$ISPUBLIC$$MethodName$(";
313 grpc::string callback =
314 "callback: (error: grpc.ServiceError | null, response: "
315 "$FBSFile$.$INPUT$) => void): "
316 "grpc.ClientWritableStream<$FBSFile$.$OUTPUT$>;\n";
317 auto meta_data = GenerateMetaData() + ", ";
318 auto options = GenerateOptions() + ", ";
319 printer->Print(vars, (main + callback).c_str());
320 printer->Print(vars, (main + meta_data + callback).c_str());
321 printer->Print(vars, (main + options + callback).c_str());
322 printer->Print(vars, (main + meta_data + options + callback).c_str());
323}
324
325void GenerateClientReadableStreamInterface(
326 grpc_generator::Printer *printer,
327 std::map<grpc::string, grpc::string> *dictonary) {
328 auto vars = *dictonary;
329 grpc::string main = "$ISPUBLIC$$MethodName$(request: $FBSFile$.$INPUT$, ";
330 grpc::string end_function =
331 "): grpc.ClientReadableStream<$FBSFile$.$OUTPUT$>;\n";
332 auto meta_data = GenerateMetaData();
333 auto options = GenerateOptions();
334 printer->Print(vars, (main + meta_data + end_function).c_str());
335 printer->Print(vars, (main + options + end_function).c_str());
336}
337
338void GenerateDepluxStreamInterface(
339 grpc_generator::Printer *printer,
340 std::map<grpc::string, grpc::string> *dictonary) {
341 auto vars = *dictonary;
342 grpc::string main = "$ISPUBLIC$$MethodName$(";
343 grpc::string end_function =
344 "): grpc.ClientDuplexStream<$FBSFile$.$INPUT$, $FBSFile$.$OUTPUT$>;\n";
345 auto meta_data = GenerateMetaData();
346 auto options = GenerateOptions();
347 printer->Print(vars, (main + end_function).c_str());
348 printer->Print(vars, (main + options + end_function).c_str());
349 printer->Print(vars, (main + meta_data +
350 ", options?: Partial<grpc.CallOptions>" + end_function)
351 .c_str());
352}
353
354void GenerateClientInterface(const grpc_generator::Service *service,
355 grpc_generator::Printer *printer,
356 std::map<grpc::string, grpc::string> *dictonary) {
357 auto vars = *dictonary;
358 printer->Print(vars, "export interface I$ServiceName$Client {\n");
359 printer->Indent();
360 for (auto it = 0; it < service->method_count(); it++) {
361 auto method = service->method(it);
362 vars["MethodName"] = method->name();
363 vars["INPUT"] = method->get_input_type_name();
364 vars["OUTPUT"] = method->get_output_type_name();
365 vars["ISPUBLIC"] = "";
366
367 if (method->NoStreaming()) {
368 GenerateUnaryClientInterface(printer, &vars);
369 continue;
370 }
371 if (method->BidiStreaming()) {
372 GenerateDepluxStreamInterface(printer, &vars);
373 continue;
374 }
375
376 if (method->ClientStreaming()) {
377 GenerateClientWriteStreamInterface(printer, &vars);
378 continue;
379 }
380
381 if (method->ServerStreaming()) {
382 GenerateClientReadableStreamInterface(printer, &vars);
383 continue;
384 }
385 }
386 printer->Outdent();
387 printer->Print("}\n");
388}
389
390void GenerateClientClassInterface(
391 const grpc_generator::Service *service, grpc_generator::Printer *printer,
392 std::map<grpc::string, grpc::string> *dictonary) {
393 auto vars = *dictonary;
394 printer->Print(vars,
395 "export class $ServiceName$Client extends grpc.Client "
396 "implements I$ServiceName$Client {\n");
397 printer->Indent();
398 printer->Print(
399 "constructor(address: string, credentials: grpc.ChannelCredentials, "
400 "options?: object);");
401 for (auto it = 0; it < service->method_count(); it++) {
402 auto method = service->method(it);
403 vars["MethodName"] = method->name();
404 vars["INPUT"] = method->get_input_type_name();
405 vars["OUTPUT"] = method->get_output_type_name();
406 vars["ISPUBLIC"] = "public ";
407 if (method->NoStreaming()) {
408 GenerateUnaryClientInterface(printer, &vars);
409 continue;
410 }
411 if (method->BidiStreaming()) {
412 GenerateDepluxStreamInterface(printer, &vars);
413 continue;
414 }
415
416 if (method->ClientStreaming()) {
417 GenerateClientWriteStreamInterface(printer, &vars);
418 continue;
419 }
420
421 if (method->ServerStreaming()) {
422 GenerateClientReadableStreamInterface(printer, &vars);
423 continue;
424 }
425 }
426 printer->Outdent();
427 printer->Print("}\n");
428}
429
430grpc::string GenerateInterface(grpc_generator::File *file,
431 const grpc_generator::Service *service,
432 const grpc::string &filename) {
433 grpc::string output;
434
435 std::set<grpc::string> generated_functions;
436 std::map<grpc::string, grpc::string> vars;
437
438 vars["PATH"] = file->package();
439
440 if (!file->package().empty()) { vars["PATH"].append("."); }
441
442 vars["ServiceName"] = service->name();
443 vars["FBSFile"] = service->name() + "_fbs";
444 vars["Filename"] = filename;
445 auto printer = file->CreatePrinter(&output);
446
447 GenerateImports(&*printer, &vars, false);
448 GenerateMainInterface(service, &*printer, &vars);
449 printer->Print("\n");
450 GenerateClientInterface(service, &*printer, &vars);
451 printer->Print("\n");
452 GenerateClientClassInterface(service, &*printer, &vars);
453 return output;
454}
455} // namespace grpc_ts_generator