diff --git a/grpc/src/compiler/swift_generator.cc b/grpc/src/compiler/swift_generator.cc index 95e8858cf..403a803ef 100644 --- a/grpc/src/compiler/swift_generator.cc +++ b/grpc/src/compiler/swift_generator.cc @@ -29,118 +29,208 @@ namespace grpc_swift_generator { -std::string WrapInNameSpace(const std::vector &components, const grpc::string &name) { +std::string WrapInNameSpace(const std::vector &components, + const grpc::string &name) { std::string qualified_name; for (auto it = components.begin(); it != components.end(); ++it) qualified_name += *it + "_"; return qualified_name + name; } -grpc::string GenerateMessage(const std::vector &components, const grpc::string &name) { +grpc::string GenerateMessage(const std::vector &components, + const grpc::string &name) { return "Message<" + WrapInNameSpace(components, name) + ">"; } // MARK: - Client -grpc::string GenerateClientFuncName(const grpc_generator::Method *method) { +void GenerateClientFuncName(const grpc_generator::Method *method, + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; if (method->NoStreaming()) { - return "$GenAccess$ func $MethodName$(_ request: $Input$" - ", callOptions: CallOptions?$isNil$) -> UnaryCall<$Input$,$Output$>"; - } - - if (method->ClientStreaming()) { - return "$GenAccess$ func $MethodName$" - "(callOptions: CallOptions?$isNil$) -> " - "ClientStreamingCall<$Input$,$Output$>"; + printer->Print(vars, + " $GenAccess$func $MethodName$(\n" + " _ request: $Input$\n" + " , callOptions: CallOptions?$isNil$\n" + " ) -> UnaryCall<$Input$, $Output$>"); + return; } if (method->ServerStreaming()) { - return "$GenAccess$ func $MethodName$(_ request: $Input$" - ", callOptions: CallOptions?$isNil$, handler: @escaping ($Output$" - ") -> Void) -> ServerStreamingCall<$Input$, $Output$>"; + printer->Print(vars, + " $GenAccess$func $MethodName$(\n" + " _ request: $Input$\n" + " , callOptions: CallOptions?$isNil$,\n" + " handler: @escaping ($Output$) -> Void\n" + " ) -> ServerStreamingCall<$Input$, $Output$>"); + return; } - return "$GenAccess$ func $MethodName$" - "(callOptions: CallOptions?$isNil$, handler: @escaping ($Output$" - ") -> Void) -> BidirectionalStreamingCall<$Input$, $Output$>"; + + if (method->ClientStreaming()) { + printer->Print(vars, + " $GenAccess$func $MethodName$(\n" + " callOptions: CallOptions?$isNil$\n" + " ) -> ClientStreamingCall<$Input$, $Output$>"); + return; + } + + printer->Print(vars, + " $GenAccess$func $MethodName$(\n" + " callOptions: CallOptions?$isNil$,\n" + " handler: @escaping ($Output$ ) -> Void\n" + " ) -> BidirectionalStreamingCall<$Input$, $Output$>"); } -grpc::string GenerateClientFuncBody(const grpc_generator::Method *method) { +void GenerateClientFuncBody(const grpc_generator::Method *method, + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + vars["Interceptor"] = + "interceptors: self.interceptors?.make$MethodName$Interceptors() ?? []"; if (method->NoStreaming()) { - return "return self.makeUnaryCall(path: " - "\"/$PATH$$ServiceName$/$MethodName$\", request: request, " - "callOptions: callOptions ?? self.defaultCallOptions)"; - } - - if (method->ClientStreaming()) { - return "return self.makeClientStreamingCall(path: " - "\"/$PATH$$ServiceName$/$MethodName$\", callOptions: callOptions ?? " - "self.defaultCallOptions)"; + printer->Print( + vars, + " return self.makeUnaryCall(\n" + " path: \"/$PATH$$ServiceName$/$MethodName$\",\n" + " request: request,\n" + " callOptions: callOptions ?? self.defaultCallOptions,\n" + " $Interceptor$\n" + " )\n"); + return; } if (method->ServerStreaming()) { - return "return self.makeServerStreamingCall(path: " - "\"/$PATH$$ServiceName$/$MethodName$\", request: request, " - "callOptions: callOptions ?? self.defaultCallOptions, handler: " - "handler)"; + printer->Print( + vars, + " return self.makeServerStreamingCall(\n" + " path: \"/$PATH$$ServiceName$/$MethodName$\",\n" + " request: request,\n" + " callOptions: callOptions ?? self.defaultCallOptions,\n" + " $Interceptor$,\n" + " handler: handler\n" + " )\n"); + return; } - return "return self.makeBidirectionalStreamingCall(path: " - "\"/$PATH$$ServiceName$/$MethodName$\", callOptions: callOptions ?? " - "self.defaultCallOptions, handler: handler)"; + + if (method->ClientStreaming()) { + printer->Print( + vars, + " return self.makeClientStreamingCall(\n" + " path: \"/$PATH$$ServiceName$/$MethodName$\",\n" + " callOptions: callOptions ?? self.defaultCallOptions,\n" + " $Interceptor$\n" + " )\n"); + return; + } + printer->Print(vars, + " return self.makeBidirectionalStreamingCall(\n" + " path: \"/$PATH$$ServiceName$/$MethodName$\",\n" + " callOptions: callOptions ?? self.defaultCallOptions,\n" + " $Interceptor$,\n" + " handler: handler\n" + " )\n"); } void GenerateClientProtocol(const grpc_generator::Service *service, grpc_generator::Printer *printer, std::map *dictonary) { auto vars = *dictonary; - printer->Print(vars, "$ACCESS$ protocol $ServiceQualifiedName$Service {\n"); + printer->Print( + vars, + "$ACCESS$ protocol $ServiceQualifiedName$ClientProtocol: GRPCClient {"); + printer->Print("\n\n"); + printer->Print(" var serviceName: String { get }"); + printer->Print("\n\n"); + printer->Print( + vars, + " var interceptors: " + "$ServiceQualifiedName$ClientInterceptorFactoryProtocol? { get }"); + printer->Print("\n\n"); + vars["GenAccess"] = ""; for (auto it = 0; it < service->method_count(); it++) { auto method = service->method(it); - vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), method->get_input_type_name()); - vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), method->get_output_type_name()); + vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), + method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), + method->get_output_type_name()); vars["MethodName"] = method->name(); vars["isNil"] = ""; - printer->Print(" "); - auto func = GenerateClientFuncName(method.get()); - printer->Print(vars, func.c_str()); + GenerateClientFuncName(method.get(), &*printer, &vars); + printer->Print("\n\n"); + } + printer->Print("}\n\n"); + + printer->Print(vars, "extension $ServiceQualifiedName$ClientProtocol {"); + printer->Print("\n\n"); + printer->Print(vars, + " $ACCESS$ var serviceName: String { " + "\"$PATH$$ServiceName$\" }\n"); + + vars["GenAccess"] = service->is_internal() ? "internal " : "public "; + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), + method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), + method->get_output_type_name()); + vars["MethodName"] = method->name(); + vars["isNil"] = " = nil"; printer->Print("\n"); + GenerateClientFuncName(method.get(), &*printer, &vars); + printer->Print(" {\n"); + GenerateClientFuncBody(method.get(), &*printer, &vars); + printer->Print(" }\n"); + } + printer->Print("}\n\n"); + + printer->Print(vars, + "$ACCESS$ protocol " + "$ServiceQualifiedName$ClientInterceptorFactoryProtocol {\n"); + + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), + method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), + method->get_output_type_name()); + vars["MethodName"] = method->name(); + printer->Print( + vars, + " /// - Returns: Interceptors to use when invoking '$MethodName$'.\n"); + printer->Print(vars, + " func make$MethodName$Interceptors() -> " + "[ClientInterceptor<$Input$, $Output$>]\n\n"); } printer->Print("}\n\n"); } -void GenerateClientClass(const grpc_generator::Service *service, - grpc_generator::Printer *printer, +void GenerateClientClass(grpc_generator::Printer *printer, std::map *dictonary) { auto vars = *dictonary; printer->Print(vars, - "$ACCESS$ final class $ServiceQualifiedName$ServiceClient: GRPCClient, " - "$ServiceQualifiedName$Service {\n"); + "$ACCESS$ final class $ServiceQualifiedName$ServiceClient: " + "$ServiceQualifiedName$ClientProtocol {\n"); printer->Print(vars, " $ACCESS$ let channel: GRPCChannel\n"); printer->Print(vars, " $ACCESS$ var defaultCallOptions: CallOptions\n"); - printer->Print("\n"); printer->Print(vars, - " $ACCESS$ init(channel: GRPCChannel, " - "defaultCallOptions: CallOptions = CallOptions()) {\n"); + " $ACCESS$ var interceptors: " + "$ServiceQualifiedName$ClientInterceptorFactoryProtocol?\n"); + printer->Print("\n"); + printer->Print( + vars, + " $ACCESS$ init(\n" + " channel: GRPCChannel,\n" + " defaultCallOptions: CallOptions = CallOptions(),\n" + " interceptors: " + "$ServiceQualifiedName$ClientInterceptorFactoryProtocol? = nil\n" + " ) {\n"); printer->Print(" self.channel = channel\n"); printer->Print(" self.defaultCallOptions = defaultCallOptions\n"); + printer->Print(" self.interceptors = interceptors\n"); printer->Print(" }"); printer->Print("\n"); - vars["GenAccess"] = service->is_internal() ? "internal" : "public"; - for (auto it = 0; it < service->method_count(); it++) { - auto method = service->method(it); - vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), method->get_input_type_name()); - vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), method->get_output_type_name()); - vars["MethodName"] = method->name(); - vars["isNil"] = " = nil"; - printer->Print("\n "); - auto func = GenerateClientFuncName(method.get()); - printer->Print(vars, func.c_str()); - printer->Print(" {\n"); - auto body = GenerateClientFuncBody(method.get()); - printer->Print(" "); - printer->Print(vars, body.c_str()); - printer->Print("\n }\n"); - } printer->Print("}\n"); } @@ -148,7 +238,7 @@ void GenerateClientClass(const grpc_generator::Service *service, grpc::string GenerateServerFuncName(const grpc_generator::Method *method) { if (method->NoStreaming()) { - return "func $MethodName$(_ request: $Input$" + return "func $MethodName$(request: $Input$" ", context: StatusOnlyCallContext) -> EventLoopFuture<$Output$>"; } @@ -169,43 +259,44 @@ grpc::string GenerateServerFuncName(const grpc_generator::Method *method) { grpc::string GenerateServerExtensionBody(const grpc_generator::Method *method) { grpc::string start = " case \"$MethodName$\":\n "; + grpc::string interceptors = + " interceptors: self.interceptors?.make$MethodName$Interceptors() " + "?? [],\n"; if (method->NoStreaming()) { return start + - "return CallHandlerFactory.makeUnary(callHandlerContext: callHandlerContext) { " - "context in" - "\n " - "return { request in" - "\n " - "self.$MethodName$(request, context: context)" - "\n }" - "\n }"; - } - if (method->ClientStreaming()) { - return start + - "return CallHandlerFactory.makeClientStreaming(callHandlerContext: " - "callHandlerContext) { context in" - "\n " - "self.$MethodName$(context: context)" - "\n }"; + "return UnaryServerHandler(\n" + " context: context,\n" + " requestDeserializer: GRPCPayloadDeserializer<$Input$>(),\n" + " responseSerializer: GRPCPayloadSerializer<$Output$>(),\n" + + interceptors + + " userFunction: self.$MethodName$(request:context:))\n"; } if (method->ServerStreaming()) { return start + - "return CallHandlerFactory.makeServerStreaming(callHandlerContext: " - "callHandlerContext) { context in" - "\n " - "return { request in" - "\n " - "self.$MethodName$(request: request, context: context)" - "\n }" - "\n }"; + "return ServerStreamingServerHandler(\n" + " context: context,\n" + " requestDeserializer: GRPCPayloadDeserializer<$Input$>(),\n" + " responseSerializer: GRPCPayloadSerializer<$Output$>(),\n" + + interceptors + + " userFunction: self.$MethodName$(request:context:))\n"; + } + if (method->ClientStreaming()) { + return start + + "return ClientStreamingServerHandler(\n" + " context: context,\n" + " requestDeserializer: GRPCPayloadDeserializer<$Input$>(),\n" + " responseSerializer: GRPCPayloadSerializer<$Output$>(),\n" + + interceptors + + " observerFactory: self.$MethodName$(context:))\n"; } if (method->BidiStreaming()) { return start + - "return CallHandlerFactory.makeBidirectionalStreaming(callHandlerContext: " - "callHandlerContext) { context in" - "\n " - "self.$MethodName$(context: context)" - "\n }"; + "return BidirectionalStreamingServerHandler(\n" + " context: context,\n" + " requestDeserializer: GRPCPayloadDeserializer<$Input$>(),\n" + " responseSerializer: GRPCPayloadSerializer<$Output$>(),\n" + + interceptors + + " observerFactory: self.$MethodName$(context:))\n"; } return ""; } @@ -214,12 +305,19 @@ void GenerateServerProtocol(const grpc_generator::Service *service, grpc_generator::Printer *printer, std::map *dictonary) { auto vars = *dictonary; + printer->Print(vars, + "$ACCESS$ protocol $ServiceQualifiedName$Provider: " + "CallHandlerProvider {\n"); printer->Print( - vars, "$ACCESS$ protocol $ServiceQualifiedName$Provider: CallHandlerProvider {\n"); + vars, + " var interceptors: " + "$ServiceQualifiedName$ServerInterceptorFactoryProtocol? { get }\n"); for (auto it = 0; it < service->method_count(); it++) { auto method = service->method(it); - vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), method->get_input_type_name()); - vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), method->get_output_type_name()); + vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), + method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), + method->get_output_type_name()); vars["MethodName"] = method->name(); printer->Print(" "); auto func = GenerateServerFuncName(method.get()); @@ -235,13 +333,15 @@ void GenerateServerProtocol(const grpc_generator::Service *service, "\"$PATH$$ServiceName$\" }\n"); printer->Print("\n"); printer->Print( - " func handleMethod(_ methodName: Substring, callHandlerContext: " - "CallHandlerContext) -> GRPCCallHandler? {\n"); - printer->Print(" switch methodName {\n"); + " func handle(method name: Substring, context: " + "CallHandlerContext) -> GRPCServerHandlerProtocol? {\n"); + printer->Print(" switch name {\n"); for (auto it = 0; it < service->method_count(); it++) { auto method = service->method(it); - vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), method->get_input_type_name()); - vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), method->get_output_type_name()); + vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), + method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), + method->get_output_type_name()); vars["MethodName"] = method->name(); auto body = GenerateServerExtensionBody(method.get()); printer->Print(vars, body.c_str()); @@ -250,6 +350,26 @@ void GenerateServerProtocol(const grpc_generator::Service *service, printer->Print(" default: return nil;\n"); printer->Print(" }\n"); printer->Print(" }\n\n"); + printer->Print("}\n\n"); + + printer->Print(vars, + "$ACCESS$ protocol " + "$ServiceQualifiedName$ServerInterceptorFactoryProtocol {\n"); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), + method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), + method->get_output_type_name()); + vars["MethodName"] = method->name(); + printer->Print( + vars, + " /// - Returns: Interceptors to use when handling '$MethodName$'.\n" + " /// Defaults to calling `self.makeInterceptors()`.\n"); + printer->Print(vars, + " func make$MethodName$Interceptors() -> " + "[ServerInterceptor<$Input$, $Output$>]\n\n"); + } printer->Print("}"); } @@ -259,15 +379,17 @@ grpc::string Generate(grpc_generator::File *file, std::map vars; vars["PATH"] = file->package(); if (!file->package().empty()) { vars["PATH"].append("."); } - vars["ServiceQualifiedName"] = WrapInNameSpace(service->namespace_parts(), service->name()); + vars["ServiceQualifiedName"] = + WrapInNameSpace(service->namespace_parts(), service->name()); vars["ServiceName"] = service->name(); vars["ACCESS"] = service->is_internal() ? "internal" : "public"; auto printer = file->CreatePrinter(&output); - printer->Print(vars, - "/// Usage: instantiate $ServiceQualifiedName$ServiceClient, then call " - "methods of this protocol to make API calls.\n"); + printer->Print( + vars, + "/// Usage: instantiate $ServiceQualifiedName$ServiceClient, then call " + "methods of this protocol to make API calls.\n"); GenerateClientProtocol(service, &*printer, &vars); - GenerateClientClass(service, &*printer, &vars); + GenerateClientClass(&*printer, &vars); printer->Print("\n"); GenerateServerProtocol(service, &*printer, &vars); return output; diff --git a/swift/Sources/FlatBuffers/Message.swift b/swift/Sources/FlatBuffers/Message.swift index b8bba0323..52ae487b2 100644 --- a/swift/Sources/FlatBuffers/Message.swift +++ b/swift/Sources/FlatBuffers/Message.swift @@ -27,7 +27,7 @@ public protocol FlatBufferGRPCMessage { /// Message is a wrapper around Buffers to to able to send Flatbuffers `Buffers` through the /// GRPC library -public final class Message: FlatBufferGRPCMessage { +public struct Message: FlatBufferGRPCMessage { internal var buffer: ByteBuffer /// Returns the an object of type T that would be read from the buffer diff --git a/tests/FlatBuffers.GRPC.Swift/Package.swift b/tests/FlatBuffers.GRPC.Swift/Package.swift index ee9adc23c..5692439d9 100644 --- a/tests/FlatBuffers.GRPC.Swift/Package.swift +++ b/tests/FlatBuffers.GRPC.Swift/Package.swift @@ -25,7 +25,7 @@ let package = Package( ], dependencies: [ .package(path: "../../swift"), - .package(url: "https://github.com/grpc/grpc-swift.git", from: "1.0.0-alpha.19"), + .package(url: "https://github.com/grpc/grpc-swift.git", .exact("1.0.0-alpha.24")), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/tests/FlatBuffers.GRPC.Swift/Sources/Model/greeter.grpc.swift b/tests/FlatBuffers.GRPC.Swift/Sources/Model/greeter.grpc.swift index e4605e03d..aacffe5ce 100644 --- a/tests/FlatBuffers.GRPC.Swift/Sources/Model/greeter.grpc.swift +++ b/tests/FlatBuffers.GRPC.Swift/Sources/Model/greeter.grpc.swift @@ -24,31 +24,84 @@ public extension GRPCFlatBufPayload { extension Message: GRPCFlatBufPayload {} /// Usage: instantiate GreeterServiceClient, then call methods of this protocol to make API calls. -public protocol GreeterService { - func SayHello(_ request: Message, callOptions: CallOptions?) -> UnaryCall,Message> - func SayManyHellos(_ request: Message, callOptions: CallOptions?, handler: @escaping (Message) -> Void) -> ServerStreamingCall, Message> +public protocol GreeterClientProtocol: GRPCClient { + + var serviceName: String { get } + + var interceptors: GreeterClientInterceptorFactoryProtocol? { get } + + func SayHello( + _ request: Message + , callOptions: CallOptions? + ) -> UnaryCall, Message> + + func SayManyHellos( + _ request: Message + , callOptions: CallOptions?, + handler: @escaping (Message) -> Void + ) -> ServerStreamingCall, Message> + } -public final class GreeterServiceClient: GRPCClient, GreeterService { +extension GreeterClientProtocol { + + public var serviceName: String { "Greeter" } + + public func SayHello( + _ request: Message + , callOptions: CallOptions? = nil + ) -> UnaryCall, Message> { + return self.makeUnaryCall( + path: "/Greeter/SayHello", + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeSayHelloInterceptors() ?? [] + ) + } + + public func SayManyHellos( + _ request: Message + , callOptions: CallOptions? = nil, + handler: @escaping (Message) -> Void + ) -> ServerStreamingCall, Message> { + return self.makeServerStreamingCall( + path: "/Greeter/SayManyHellos", + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeSayManyHellosInterceptors() ?? [], + handler: handler + ) + } +} + +public protocol GreeterClientInterceptorFactoryProtocol { + /// - Returns: Interceptors to use when invoking 'SayHello'. + func makeSayHelloInterceptors() -> [ClientInterceptor, Message>] + + /// - Returns: Interceptors to use when invoking 'SayManyHellos'. + func makeSayManyHellosInterceptors() -> [ClientInterceptor, Message>] + +} + +public final class GreeterServiceClient: GreeterClientProtocol { public let channel: GRPCChannel public var defaultCallOptions: CallOptions + public var interceptors: GreeterClientInterceptorFactoryProtocol? - public init(channel: GRPCChannel, defaultCallOptions: CallOptions = CallOptions()) { + public init( + channel: GRPCChannel, + defaultCallOptions: CallOptions = CallOptions(), + interceptors: GreeterClientInterceptorFactoryProtocol? = nil + ) { self.channel = channel self.defaultCallOptions = defaultCallOptions - } - - public func SayHello(_ request: Message, callOptions: CallOptions? = nil) -> UnaryCall,Message> { - return self.makeUnaryCall(path: "/Greeter/SayHello", request: request, callOptions: callOptions ?? self.defaultCallOptions) - } - - public func SayManyHellos(_ request: Message, callOptions: CallOptions? = nil, handler: @escaping (Message) -> Void) -> ServerStreamingCall, Message> { - return self.makeServerStreamingCall(path: "/Greeter/SayManyHellos", request: request, callOptions: callOptions ?? self.defaultCallOptions, handler: handler) + self.interceptors = interceptors } } public protocol GreeterProvider: CallHandlerProvider { - func SayHello(_ request: Message, context: StatusOnlyCallContext) -> EventLoopFuture> + var interceptors: GreeterServerInterceptorFactoryProtocol? { get } + func SayHello(request: Message, context: StatusOnlyCallContext) -> EventLoopFuture> func SayManyHellos(request: Message, context: StreamingResponseCallContext>) -> EventLoopFuture } @@ -56,22 +109,37 @@ public extension GreeterProvider { var serviceName: Substring { return "Greeter" } - func handleMethod(_ methodName: Substring, callHandlerContext: CallHandlerContext) -> GRPCCallHandler? { - switch methodName { + func handle(method name: Substring, context: CallHandlerContext) -> GRPCServerHandlerProtocol? { + switch name { case "SayHello": - return CallHandlerFactory.makeUnary(callHandlerContext: callHandlerContext) { context in - return { request in - self.SayHello(request, context: context) - } - } + return UnaryServerHandler( + context: context, + requestDeserializer: GRPCPayloadDeserializer>(), + responseSerializer: GRPCPayloadSerializer>(), + interceptors: self.interceptors?.makeSayHelloInterceptors() ?? [], + userFunction: self.SayHello(request:context:)) + case "SayManyHellos": - return CallHandlerFactory.makeServerStreaming(callHandlerContext: callHandlerContext) { context in - return { request in - self.SayManyHellos(request: request, context: context) - } - } + return ServerStreamingServerHandler( + context: context, + requestDeserializer: GRPCPayloadDeserializer>(), + responseSerializer: GRPCPayloadSerializer>(), + interceptors: self.interceptors?.makeSayManyHellosInterceptors() ?? [], + userFunction: self.SayManyHellos(request:context:)) + default: return nil; } } } + +public protocol GreeterServerInterceptorFactoryProtocol { + /// - Returns: Interceptors to use when handling 'SayHello'. + /// Defaults to calling `self.makeInterceptors()`. + func makeSayHelloInterceptors() -> [ServerInterceptor, Message>] + + /// - Returns: Interceptors to use when handling 'SayManyHellos'. + /// Defaults to calling `self.makeInterceptors()`. + func makeSayManyHellosInterceptors() -> [ServerInterceptor, Message>] + +} diff --git a/tests/FlatBuffers.GRPC.Swift/Sources/server/main.swift b/tests/FlatBuffers.GRPC.Swift/Sources/server/main.swift index 53c02230c..d5274c1b3 100644 --- a/tests/FlatBuffers.GRPC.Swift/Sources/server/main.swift +++ b/tests/FlatBuffers.GRPC.Swift/Sources/server/main.swift @@ -22,6 +22,8 @@ import NIO class Greeter: GreeterProvider { + var interceptors: GreeterServerInterceptorFactoryProtocol? + var hellos: [Message] = [] init() { @@ -36,7 +38,7 @@ class Greeter: GreeterProvider { } func SayHello( - _ request: Message, + request: Message, context: StatusOnlyCallContext) -> EventLoopFuture> { let recipient = request.object.name ?? "Stranger" diff --git a/tests/FlatBuffers.Test.Swift/Package.swift b/tests/FlatBuffers.Test.Swift/Package.swift index 06d03bd4f..ee8e9d6fe 100644 --- a/tests/FlatBuffers.Test.Swift/Package.swift +++ b/tests/FlatBuffers.Test.Swift/Package.swift @@ -25,7 +25,7 @@ let package = Package( ], dependencies: [ .package(path: "../../swift/"), - .package(url: "https://github.com/grpc/grpc-swift.git", from: "1.0.0-alpha.19"), + .package(url: "https://github.com/grpc/grpc-swift.git", .exact("1.0.0-alpha.24")), ], targets: [ .target(name: "SwiftFlatBuffers"), diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test.grpc.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test.grpc.swift index 414a816d6..b5fd53596 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test.grpc.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test.grpc.swift @@ -24,41 +24,121 @@ public extension GRPCFlatBufPayload { extension Message: GRPCFlatBufPayload {} /// Usage: instantiate MyGame_Example_MonsterStorageServiceClient, then call methods of this protocol to make API calls. -public protocol MyGame_Example_MonsterStorageService { - func Store(_ request: Message, callOptions: CallOptions?) -> UnaryCall,Message> - func Retrieve(_ request: Message, callOptions: CallOptions?, handler: @escaping (Message) -> Void) -> ServerStreamingCall, Message> - func GetMaxHitPoint(callOptions: CallOptions?) -> ClientStreamingCall,Message> - func GetMinMaxHitPoints(callOptions: CallOptions?, handler: @escaping (Message) -> Void) -> BidirectionalStreamingCall, Message> +public protocol MyGame_Example_MonsterStorageClientProtocol: GRPCClient { + + var serviceName: String { get } + + var interceptors: MyGame_Example_MonsterStorageClientInterceptorFactoryProtocol? { get } + + func Store( + _ request: Message + , callOptions: CallOptions? + ) -> UnaryCall, Message> + + func Retrieve( + _ request: Message + , callOptions: CallOptions?, + handler: @escaping (Message) -> Void + ) -> ServerStreamingCall, Message> + + func GetMaxHitPoint( + callOptions: CallOptions? + ) -> ClientStreamingCall, Message> + + func GetMinMaxHitPoints( + callOptions: CallOptions?, + handler: @escaping (Message ) -> Void + ) -> BidirectionalStreamingCall, Message> + } -public final class MyGame_Example_MonsterStorageServiceClient: GRPCClient, MyGame_Example_MonsterStorageService { +extension MyGame_Example_MonsterStorageClientProtocol { + + public var serviceName: String { "MyGame.Example.MonsterStorage" } + + public func Store( + _ request: Message + , callOptions: CallOptions? = nil + ) -> UnaryCall, Message> { + return self.makeUnaryCall( + path: "/MyGame.Example.MonsterStorage/Store", + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeStoreInterceptors() ?? [] + ) + } + + public func Retrieve( + _ request: Message + , callOptions: CallOptions? = nil, + handler: @escaping (Message) -> Void + ) -> ServerStreamingCall, Message> { + return self.makeServerStreamingCall( + path: "/MyGame.Example.MonsterStorage/Retrieve", + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeRetrieveInterceptors() ?? [], + handler: handler + ) + } + + public func GetMaxHitPoint( + callOptions: CallOptions? = nil + ) -> ClientStreamingCall, Message> { + return self.makeClientStreamingCall( + path: "/MyGame.Example.MonsterStorage/GetMaxHitPoint", + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeGetMaxHitPointInterceptors() ?? [] + ) + } + + public func GetMinMaxHitPoints( + callOptions: CallOptions? = nil, + handler: @escaping (Message ) -> Void + ) -> BidirectionalStreamingCall, Message> { + return self.makeBidirectionalStreamingCall( + path: "/MyGame.Example.MonsterStorage/GetMinMaxHitPoints", + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeGetMinMaxHitPointsInterceptors() ?? [], + handler: handler + ) + } +} + +public protocol MyGame_Example_MonsterStorageClientInterceptorFactoryProtocol { + /// - Returns: Interceptors to use when invoking 'Store'. + func makeStoreInterceptors() -> [ClientInterceptor, Message>] + + /// - Returns: Interceptors to use when invoking 'Retrieve'. + func makeRetrieveInterceptors() -> [ClientInterceptor, Message>] + + /// - Returns: Interceptors to use when invoking 'GetMaxHitPoint'. + func makeGetMaxHitPointInterceptors() -> [ClientInterceptor, Message>] + + /// - Returns: Interceptors to use when invoking 'GetMinMaxHitPoints'. + func makeGetMinMaxHitPointsInterceptors() -> [ClientInterceptor, Message>] + +} + +public final class MyGame_Example_MonsterStorageServiceClient: MyGame_Example_MonsterStorageClientProtocol { public let channel: GRPCChannel public var defaultCallOptions: CallOptions + public var interceptors: MyGame_Example_MonsterStorageClientInterceptorFactoryProtocol? - public init(channel: GRPCChannel, defaultCallOptions: CallOptions = CallOptions()) { + public init( + channel: GRPCChannel, + defaultCallOptions: CallOptions = CallOptions(), + interceptors: MyGame_Example_MonsterStorageClientInterceptorFactoryProtocol? = nil + ) { self.channel = channel self.defaultCallOptions = defaultCallOptions - } - - public func Store(_ request: Message, callOptions: CallOptions? = nil) -> UnaryCall,Message> { - return self.makeUnaryCall(path: "/MyGame.Example.MonsterStorage/Store", request: request, callOptions: callOptions ?? self.defaultCallOptions) - } - - public func Retrieve(_ request: Message, callOptions: CallOptions? = nil, handler: @escaping (Message) -> Void) -> ServerStreamingCall, Message> { - return self.makeServerStreamingCall(path: "/MyGame.Example.MonsterStorage/Retrieve", request: request, callOptions: callOptions ?? self.defaultCallOptions, handler: handler) - } - - public func GetMaxHitPoint(callOptions: CallOptions? = nil) -> ClientStreamingCall,Message> { - return self.makeClientStreamingCall(path: "/MyGame.Example.MonsterStorage/GetMaxHitPoint", callOptions: callOptions ?? self.defaultCallOptions) - } - - public func GetMinMaxHitPoints(callOptions: CallOptions? = nil, handler: @escaping (Message) -> Void) -> BidirectionalStreamingCall, Message> { - return self.makeBidirectionalStreamingCall(path: "/MyGame.Example.MonsterStorage/GetMinMaxHitPoints", callOptions: callOptions ?? self.defaultCallOptions, handler: handler) + self.interceptors = interceptors } } public protocol MyGame_Example_MonsterStorageProvider: CallHandlerProvider { - func Store(_ request: Message, context: StatusOnlyCallContext) -> EventLoopFuture> + var interceptors: MyGame_Example_MonsterStorageServerInterceptorFactoryProtocol? { get } + func Store(request: Message, context: StatusOnlyCallContext) -> EventLoopFuture> func Retrieve(request: Message, context: StreamingResponseCallContext>) -> EventLoopFuture func GetMaxHitPoint(context: UnaryResponseCallContext>) -> EventLoopFuture<(StreamEvent>) -> Void> func GetMinMaxHitPoints(context: StreamingResponseCallContext>) -> EventLoopFuture<(StreamEvent>) -> Void> @@ -68,30 +148,61 @@ public extension MyGame_Example_MonsterStorageProvider { var serviceName: Substring { return "MyGame.Example.MonsterStorage" } - func handleMethod(_ methodName: Substring, callHandlerContext: CallHandlerContext) -> GRPCCallHandler? { - switch methodName { + func handle(method name: Substring, context: CallHandlerContext) -> GRPCServerHandlerProtocol? { + switch name { case "Store": - return CallHandlerFactory.makeUnary(callHandlerContext: callHandlerContext) { context in - return { request in - self.Store(request, context: context) - } - } + return UnaryServerHandler( + context: context, + requestDeserializer: GRPCPayloadDeserializer>(), + responseSerializer: GRPCPayloadSerializer>(), + interceptors: self.interceptors?.makeStoreInterceptors() ?? [], + userFunction: self.Store(request:context:)) + case "Retrieve": - return CallHandlerFactory.makeServerStreaming(callHandlerContext: callHandlerContext) { context in - return { request in - self.Retrieve(request: request, context: context) - } - } + return ServerStreamingServerHandler( + context: context, + requestDeserializer: GRPCPayloadDeserializer>(), + responseSerializer: GRPCPayloadSerializer>(), + interceptors: self.interceptors?.makeRetrieveInterceptors() ?? [], + userFunction: self.Retrieve(request:context:)) + case "GetMaxHitPoint": - return CallHandlerFactory.makeClientStreaming(callHandlerContext: callHandlerContext) { context in - self.GetMaxHitPoint(context: context) - } + return ClientStreamingServerHandler( + context: context, + requestDeserializer: GRPCPayloadDeserializer>(), + responseSerializer: GRPCPayloadSerializer>(), + interceptors: self.interceptors?.makeGetMaxHitPointInterceptors() ?? [], + observerFactory: self.GetMaxHitPoint(context:)) + case "GetMinMaxHitPoints": - return CallHandlerFactory.makeBidirectionalStreaming(callHandlerContext: callHandlerContext) { context in - self.GetMinMaxHitPoints(context: context) - } + return BidirectionalStreamingServerHandler( + context: context, + requestDeserializer: GRPCPayloadDeserializer>(), + responseSerializer: GRPCPayloadSerializer>(), + interceptors: self.interceptors?.makeGetMinMaxHitPointsInterceptors() ?? [], + observerFactory: self.GetMinMaxHitPoints(context:)) + default: return nil; } } } + +public protocol MyGame_Example_MonsterStorageServerInterceptorFactoryProtocol { + /// - Returns: Interceptors to use when handling 'Store'. + /// Defaults to calling `self.makeInterceptors()`. + func makeStoreInterceptors() -> [ServerInterceptor, Message>] + + /// - Returns: Interceptors to use when handling 'Retrieve'. + /// Defaults to calling `self.makeInterceptors()`. + func makeRetrieveInterceptors() -> [ServerInterceptor, Message>] + + /// - Returns: Interceptors to use when handling 'GetMaxHitPoint'. + /// Defaults to calling `self.makeInterceptors()`. + func makeGetMaxHitPointInterceptors() -> [ServerInterceptor, Message>] + + /// - Returns: Interceptors to use when handling 'GetMinMaxHitPoints'. + /// Defaults to calling `self.makeInterceptors()`. + func makeGetMinMaxHitPointsInterceptors() -> [ServerInterceptor, Message>] + +}