blob: 403a803ef112f1d70a144952817691e5b1144544 [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#include <map>
24#include <sstream>
25
26#include "flatbuffers/util.h"
27#include "src/compiler/schema_interface.h"
28#include "src/compiler/swift_generator.h"
29
30namespace grpc_swift_generator {
31
James Kuszmaul8e62b022022-03-22 09:33:25 -070032std::string WrapInNameSpace(const std::vector<std::string> &components,
33 const grpc::string &name) {
Austin Schuh272c6132020-11-14 16:37:52 -080034 std::string qualified_name;
35 for (auto it = components.begin(); it != components.end(); ++it)
36 qualified_name += *it + "_";
37 return qualified_name + name;
38}
39
James Kuszmaul8e62b022022-03-22 09:33:25 -070040grpc::string GenerateMessage(const std::vector<std::string> &components,
41 const grpc::string &name) {
Austin Schuh272c6132020-11-14 16:37:52 -080042 return "Message<" + WrapInNameSpace(components, name) + ">";
43}
44
45// MARK: - Client
46
James Kuszmaul8e62b022022-03-22 09:33:25 -070047void GenerateClientFuncName(const grpc_generator::Method *method,
48 grpc_generator::Printer *printer,
49 std::map<grpc::string, grpc::string> *dictonary) {
50 auto vars = *dictonary;
Austin Schuh272c6132020-11-14 16:37:52 -080051 if (method->NoStreaming()) {
James Kuszmaul8e62b022022-03-22 09:33:25 -070052 printer->Print(vars,
53 " $GenAccess$func $MethodName$(\n"
54 " _ request: $Input$\n"
55 " , callOptions: CallOptions?$isNil$\n"
56 " ) -> UnaryCall<$Input$, $Output$>");
57 return;
Austin Schuh272c6132020-11-14 16:37:52 -080058 }
59
60 if (method->ServerStreaming()) {
James Kuszmaul8e62b022022-03-22 09:33:25 -070061 printer->Print(vars,
62 " $GenAccess$func $MethodName$(\n"
63 " _ request: $Input$\n"
64 " , callOptions: CallOptions?$isNil$,\n"
65 " handler: @escaping ($Output$) -> Void\n"
66 " ) -> ServerStreamingCall<$Input$, $Output$>");
67 return;
Austin Schuh272c6132020-11-14 16:37:52 -080068 }
James Kuszmaul8e62b022022-03-22 09:33:25 -070069
70 if (method->ClientStreaming()) {
71 printer->Print(vars,
72 " $GenAccess$func $MethodName$(\n"
73 " callOptions: CallOptions?$isNil$\n"
74 " ) -> ClientStreamingCall<$Input$, $Output$>");
75 return;
76 }
77
78 printer->Print(vars,
79 " $GenAccess$func $MethodName$(\n"
80 " callOptions: CallOptions?$isNil$,\n"
81 " handler: @escaping ($Output$ ) -> Void\n"
82 " ) -> BidirectionalStreamingCall<$Input$, $Output$>");
Austin Schuh272c6132020-11-14 16:37:52 -080083}
84
James Kuszmaul8e62b022022-03-22 09:33:25 -070085void GenerateClientFuncBody(const grpc_generator::Method *method,
86 grpc_generator::Printer *printer,
87 std::map<grpc::string, grpc::string> *dictonary) {
88 auto vars = *dictonary;
89 vars["Interceptor"] =
90 "interceptors: self.interceptors?.make$MethodName$Interceptors() ?? []";
Austin Schuh272c6132020-11-14 16:37:52 -080091 if (method->NoStreaming()) {
James Kuszmaul8e62b022022-03-22 09:33:25 -070092 printer->Print(
93 vars,
94 " return self.makeUnaryCall(\n"
95 " path: \"/$PATH$$ServiceName$/$MethodName$\",\n"
96 " request: request,\n"
97 " callOptions: callOptions ?? self.defaultCallOptions,\n"
98 " $Interceptor$\n"
99 " )\n");
100 return;
Austin Schuh272c6132020-11-14 16:37:52 -0800101 }
102
103 if (method->ServerStreaming()) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700104 printer->Print(
105 vars,
106 " return self.makeServerStreamingCall(\n"
107 " path: \"/$PATH$$ServiceName$/$MethodName$\",\n"
108 " request: request,\n"
109 " callOptions: callOptions ?? self.defaultCallOptions,\n"
110 " $Interceptor$,\n"
111 " handler: handler\n"
112 " )\n");
113 return;
Austin Schuh272c6132020-11-14 16:37:52 -0800114 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700115
116 if (method->ClientStreaming()) {
117 printer->Print(
118 vars,
119 " return self.makeClientStreamingCall(\n"
120 " path: \"/$PATH$$ServiceName$/$MethodName$\",\n"
121 " callOptions: callOptions ?? self.defaultCallOptions,\n"
122 " $Interceptor$\n"
123 " )\n");
124 return;
125 }
126 printer->Print(vars,
127 " return self.makeBidirectionalStreamingCall(\n"
128 " path: \"/$PATH$$ServiceName$/$MethodName$\",\n"
129 " callOptions: callOptions ?? self.defaultCallOptions,\n"
130 " $Interceptor$,\n"
131 " handler: handler\n"
132 " )\n");
Austin Schuh272c6132020-11-14 16:37:52 -0800133}
134
135void GenerateClientProtocol(const grpc_generator::Service *service,
136 grpc_generator::Printer *printer,
137 std::map<grpc::string, grpc::string> *dictonary) {
138 auto vars = *dictonary;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700139 printer->Print(
140 vars,
141 "$ACCESS$ protocol $ServiceQualifiedName$ClientProtocol: GRPCClient {");
142 printer->Print("\n\n");
143 printer->Print(" var serviceName: String { get }");
144 printer->Print("\n\n");
145 printer->Print(
146 vars,
147 " var interceptors: "
148 "$ServiceQualifiedName$ClientInterceptorFactoryProtocol? { get }");
149 printer->Print("\n\n");
150
Austin Schuh272c6132020-11-14 16:37:52 -0800151 vars["GenAccess"] = "";
152 for (auto it = 0; it < service->method_count(); it++) {
153 auto method = service->method(it);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700154 vars["Input"] = GenerateMessage(method->get_input_namespace_parts(),
155 method->get_input_type_name());
156 vars["Output"] = GenerateMessage(method->get_output_namespace_parts(),
157 method->get_output_type_name());
Austin Schuh272c6132020-11-14 16:37:52 -0800158 vars["MethodName"] = method->name();
159 vars["isNil"] = "";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700160 GenerateClientFuncName(method.get(), &*printer, &vars);
161 printer->Print("\n\n");
162 }
163 printer->Print("}\n\n");
164
165 printer->Print(vars, "extension $ServiceQualifiedName$ClientProtocol {");
166 printer->Print("\n\n");
167 printer->Print(vars,
168 " $ACCESS$ var serviceName: String { "
169 "\"$PATH$$ServiceName$\" }\n");
170
171 vars["GenAccess"] = service->is_internal() ? "internal " : "public ";
172 for (auto it = 0; it < service->method_count(); it++) {
173 auto method = service->method(it);
174 vars["Input"] = GenerateMessage(method->get_input_namespace_parts(),
175 method->get_input_type_name());
176 vars["Output"] = GenerateMessage(method->get_output_namespace_parts(),
177 method->get_output_type_name());
178 vars["MethodName"] = method->name();
179 vars["isNil"] = " = nil";
Austin Schuh272c6132020-11-14 16:37:52 -0800180 printer->Print("\n");
James Kuszmaul8e62b022022-03-22 09:33:25 -0700181 GenerateClientFuncName(method.get(), &*printer, &vars);
182 printer->Print(" {\n");
183 GenerateClientFuncBody(method.get(), &*printer, &vars);
184 printer->Print(" }\n");
185 }
186 printer->Print("}\n\n");
187
188 printer->Print(vars,
189 "$ACCESS$ protocol "
190 "$ServiceQualifiedName$ClientInterceptorFactoryProtocol {\n");
191
192 for (auto it = 0; it < service->method_count(); it++) {
193 auto method = service->method(it);
194 vars["Input"] = GenerateMessage(method->get_input_namespace_parts(),
195 method->get_input_type_name());
196 vars["Output"] = GenerateMessage(method->get_output_namespace_parts(),
197 method->get_output_type_name());
198 vars["MethodName"] = method->name();
199 printer->Print(
200 vars,
201 " /// - Returns: Interceptors to use when invoking '$MethodName$'.\n");
202 printer->Print(vars,
203 " func make$MethodName$Interceptors() -> "
204 "[ClientInterceptor<$Input$, $Output$>]\n\n");
Austin Schuh272c6132020-11-14 16:37:52 -0800205 }
206 printer->Print("}\n\n");
207}
208
James Kuszmaul8e62b022022-03-22 09:33:25 -0700209void GenerateClientClass(grpc_generator::Printer *printer,
Austin Schuh272c6132020-11-14 16:37:52 -0800210 std::map<grpc::string, grpc::string> *dictonary) {
211 auto vars = *dictonary;
212 printer->Print(vars,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700213 "$ACCESS$ final class $ServiceQualifiedName$ServiceClient: "
214 "$ServiceQualifiedName$ClientProtocol {\n");
Austin Schuh58b9b472020-11-25 19:12:44 -0800215 printer->Print(vars, " $ACCESS$ let channel: GRPCChannel\n");
216 printer->Print(vars, " $ACCESS$ var defaultCallOptions: CallOptions\n");
Austin Schuh272c6132020-11-14 16:37:52 -0800217 printer->Print(vars,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700218 " $ACCESS$ var interceptors: "
219 "$ServiceQualifiedName$ClientInterceptorFactoryProtocol?\n");
220 printer->Print("\n");
221 printer->Print(
222 vars,
223 " $ACCESS$ init(\n"
224 " channel: GRPCChannel,\n"
225 " defaultCallOptions: CallOptions = CallOptions(),\n"
226 " interceptors: "
227 "$ServiceQualifiedName$ClientInterceptorFactoryProtocol? = nil\n"
228 " ) {\n");
Austin Schuh58b9b472020-11-25 19:12:44 -0800229 printer->Print(" self.channel = channel\n");
230 printer->Print(" self.defaultCallOptions = defaultCallOptions\n");
James Kuszmaul8e62b022022-03-22 09:33:25 -0700231 printer->Print(" self.interceptors = interceptors\n");
Austin Schuh58b9b472020-11-25 19:12:44 -0800232 printer->Print(" }");
Austin Schuh272c6132020-11-14 16:37:52 -0800233 printer->Print("\n");
Austin Schuh272c6132020-11-14 16:37:52 -0800234 printer->Print("}\n");
235}
236
237// MARK: - Server
238
239grpc::string GenerateServerFuncName(const grpc_generator::Method *method) {
240 if (method->NoStreaming()) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700241 return "func $MethodName$(request: $Input$"
Austin Schuh272c6132020-11-14 16:37:52 -0800242 ", context: StatusOnlyCallContext) -> EventLoopFuture<$Output$>";
243 }
244
245 if (method->ClientStreaming()) {
246 return "func $MethodName$(context: UnaryResponseCallContext<$Output$>) -> "
247 "EventLoopFuture<(StreamEvent<$Input$"
248 ">) -> Void>";
249 }
250
251 if (method->ServerStreaming()) {
252 return "func $MethodName$(request: $Input$"
253 ", context: StreamingResponseCallContext<$Output$>) -> "
254 "EventLoopFuture<GRPCStatus>";
255 }
256 return "func $MethodName$(context: StreamingResponseCallContext<$Output$>) "
257 "-> EventLoopFuture<(StreamEvent<$Input$>) -> Void>";
258}
259
260grpc::string GenerateServerExtensionBody(const grpc_generator::Method *method) {
Austin Schuh58b9b472020-11-25 19:12:44 -0800261 grpc::string start = " case \"$MethodName$\":\n ";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700262 grpc::string interceptors =
263 " interceptors: self.interceptors?.make$MethodName$Interceptors() "
264 "?? [],\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800265 if (method->NoStreaming()) {
266 return start +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700267 "return UnaryServerHandler(\n"
268 " context: context,\n"
269 " requestDeserializer: GRPCPayloadDeserializer<$Input$>(),\n"
270 " responseSerializer: GRPCPayloadSerializer<$Output$>(),\n" +
271 interceptors +
272 " userFunction: self.$MethodName$(request:context:))\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800273 }
274 if (method->ServerStreaming()) {
275 return start +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700276 "return ServerStreamingServerHandler(\n"
277 " context: context,\n"
278 " requestDeserializer: GRPCPayloadDeserializer<$Input$>(),\n"
279 " responseSerializer: GRPCPayloadSerializer<$Output$>(),\n" +
280 interceptors +
281 " userFunction: self.$MethodName$(request:context:))\n";
282 }
283 if (method->ClientStreaming()) {
284 return start +
285 "return ClientStreamingServerHandler(\n"
286 " context: context,\n"
287 " requestDeserializer: GRPCPayloadDeserializer<$Input$>(),\n"
288 " responseSerializer: GRPCPayloadSerializer<$Output$>(),\n" +
289 interceptors +
290 " observerFactory: self.$MethodName$(context:))\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800291 }
292 if (method->BidiStreaming()) {
293 return start +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700294 "return BidirectionalStreamingServerHandler(\n"
295 " context: context,\n"
296 " requestDeserializer: GRPCPayloadDeserializer<$Input$>(),\n"
297 " responseSerializer: GRPCPayloadSerializer<$Output$>(),\n" +
298 interceptors +
299 " observerFactory: self.$MethodName$(context:))\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800300 }
301 return "";
302}
303
304void GenerateServerProtocol(const grpc_generator::Service *service,
305 grpc_generator::Printer *printer,
306 std::map<grpc::string, grpc::string> *dictonary) {
307 auto vars = *dictonary;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700308 printer->Print(vars,
309 "$ACCESS$ protocol $ServiceQualifiedName$Provider: "
310 "CallHandlerProvider {\n");
Austin Schuh272c6132020-11-14 16:37:52 -0800311 printer->Print(
James Kuszmaul8e62b022022-03-22 09:33:25 -0700312 vars,
313 " var interceptors: "
314 "$ServiceQualifiedName$ServerInterceptorFactoryProtocol? { get }\n");
Austin Schuh272c6132020-11-14 16:37:52 -0800315 for (auto it = 0; it < service->method_count(); it++) {
316 auto method = service->method(it);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700317 vars["Input"] = GenerateMessage(method->get_input_namespace_parts(),
318 method->get_input_type_name());
319 vars["Output"] = GenerateMessage(method->get_output_namespace_parts(),
320 method->get_output_type_name());
Austin Schuh272c6132020-11-14 16:37:52 -0800321 vars["MethodName"] = method->name();
Austin Schuh58b9b472020-11-25 19:12:44 -0800322 printer->Print(" ");
Austin Schuh272c6132020-11-14 16:37:52 -0800323 auto func = GenerateServerFuncName(method.get());
324 printer->Print(vars, func.c_str());
325 printer->Print("\n");
326 }
327 printer->Print("}\n\n");
328
329 printer->Print(vars, "$ACCESS$ extension $ServiceQualifiedName$Provider {\n");
330 printer->Print("\n");
331 printer->Print(vars,
Austin Schuh58b9b472020-11-25 19:12:44 -0800332 " var serviceName: Substring { return "
Austin Schuh272c6132020-11-14 16:37:52 -0800333 "\"$PATH$$ServiceName$\" }\n");
334 printer->Print("\n");
335 printer->Print(
James Kuszmaul8e62b022022-03-22 09:33:25 -0700336 " func handle(method name: Substring, context: "
337 "CallHandlerContext) -> GRPCServerHandlerProtocol? {\n");
338 printer->Print(" switch name {\n");
Austin Schuh272c6132020-11-14 16:37:52 -0800339 for (auto it = 0; it < service->method_count(); it++) {
340 auto method = service->method(it);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700341 vars["Input"] = GenerateMessage(method->get_input_namespace_parts(),
342 method->get_input_type_name());
343 vars["Output"] = GenerateMessage(method->get_output_namespace_parts(),
344 method->get_output_type_name());
Austin Schuh272c6132020-11-14 16:37:52 -0800345 vars["MethodName"] = method->name();
346 auto body = GenerateServerExtensionBody(method.get());
347 printer->Print(vars, body.c_str());
348 printer->Print("\n");
349 }
Austin Schuh58b9b472020-11-25 19:12:44 -0800350 printer->Print(" default: return nil;\n");
351 printer->Print(" }\n");
352 printer->Print(" }\n\n");
James Kuszmaul8e62b022022-03-22 09:33:25 -0700353 printer->Print("}\n\n");
354
355 printer->Print(vars,
356 "$ACCESS$ protocol "
357 "$ServiceQualifiedName$ServerInterceptorFactoryProtocol {\n");
358 for (auto it = 0; it < service->method_count(); it++) {
359 auto method = service->method(it);
360 vars["Input"] = GenerateMessage(method->get_input_namespace_parts(),
361 method->get_input_type_name());
362 vars["Output"] = GenerateMessage(method->get_output_namespace_parts(),
363 method->get_output_type_name());
364 vars["MethodName"] = method->name();
365 printer->Print(
366 vars,
367 " /// - Returns: Interceptors to use when handling '$MethodName$'.\n"
368 " /// Defaults to calling `self.makeInterceptors()`.\n");
369 printer->Print(vars,
370 " func make$MethodName$Interceptors() -> "
371 "[ServerInterceptor<$Input$, $Output$>]\n\n");
372 }
Austin Schuh58b9b472020-11-25 19:12:44 -0800373 printer->Print("}");
Austin Schuh272c6132020-11-14 16:37:52 -0800374}
375
376grpc::string Generate(grpc_generator::File *file,
377 const grpc_generator::Service *service) {
378 grpc::string output;
379 std::map<grpc::string, grpc::string> vars;
380 vars["PATH"] = file->package();
381 if (!file->package().empty()) { vars["PATH"].append("."); }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700382 vars["ServiceQualifiedName"] =
383 WrapInNameSpace(service->namespace_parts(), service->name());
Austin Schuh272c6132020-11-14 16:37:52 -0800384 vars["ServiceName"] = service->name();
385 vars["ACCESS"] = service->is_internal() ? "internal" : "public";
386 auto printer = file->CreatePrinter(&output);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700387 printer->Print(
388 vars,
389 "/// Usage: instantiate $ServiceQualifiedName$ServiceClient, then call "
390 "methods of this protocol to make API calls.\n");
Austin Schuh272c6132020-11-14 16:37:52 -0800391 GenerateClientProtocol(service, &*printer, &vars);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700392 GenerateClientClass(&*printer, &vars);
Austin Schuh272c6132020-11-14 16:37:52 -0800393 printer->Print("\n");
394 GenerateServerProtocol(service, &*printer, &vars);
395 return output;
396}
397
398grpc::string GenerateHeader() {
399 grpc::string code;
400 code +=
401 "/// The following code is generated by the Flatbuffers library which "
402 "might not be in sync with grpc-swift\n";
403 code +=
404 "/// in case of an issue please open github issue, though it would be "
405 "maintained\n";
Austin Schuh58b9b472020-11-25 19:12:44 -0800406 code += "\n";
407 code += "// swiftlint:disable all\n";
408 code += "// swiftformat:disable all\n";
409 code += "\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800410 code += "import Foundation\n";
411 code += "import GRPC\n";
412 code += "import NIO\n";
413 code += "import NIOHTTP1\n";
414 code += "import FlatBuffers\n";
415 code += "\n";
416 code +=
417 "public protocol GRPCFlatBufPayload: GRPCPayload, FlatBufferGRPCMessage "
418 "{}\n";
419
420 code += "public extension GRPCFlatBufPayload {\n";
Austin Schuh58b9b472020-11-25 19:12:44 -0800421 code += " init(serializedByteBuffer: inout NIO.ByteBuffer) throws {\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800422 code +=
Austin Schuh58b9b472020-11-25 19:12:44 -0800423 " self.init(byteBuffer: FlatBuffers.ByteBuffer(contiguousBytes: "
Austin Schuh272c6132020-11-14 16:37:52 -0800424 "serializedByteBuffer.readableBytesView, count: "
425 "serializedByteBuffer.readableBytes))\n";
Austin Schuh58b9b472020-11-25 19:12:44 -0800426 code += " }\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800427
Austin Schuh58b9b472020-11-25 19:12:44 -0800428 code += " func serialize(into buffer: inout NIO.ByteBuffer) throws {\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800429 code +=
Austin Schuh58b9b472020-11-25 19:12:44 -0800430 " let buf = UnsafeRawBufferPointer(start: self.rawPointer, count: "
Austin Schuh272c6132020-11-14 16:37:52 -0800431 "Int(self.size))\n";
Austin Schuh58b9b472020-11-25 19:12:44 -0800432 code += " buffer.writeBytes(buf)\n";
433 code += " }\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800434 code += "}\n";
435 code += "extension Message: GRPCFlatBufPayload {}\n";
436 return code;
437}
438} // namespace grpc_swift_generator