diff --git a/Examples/v2/echo/Generated/echo.grpc.swift b/Examples/v2/echo/Generated/echo.grpc.swift index 856ccc074..63a264205 100644 --- a/Examples/v2/echo/Generated/echo.grpc.swift +++ b/Examples/v2/echo/Generated/echo.grpc.swift @@ -86,16 +86,28 @@ extension GRPCCore.ServiceDescriptor { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) internal protocol Echo_EchoStreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// Immediately returns an echo of a request. - func get(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func get( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// Splits a request into words and returns each word in a stream of messages. - func expand(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func expand( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// Collects a stream of messages and returns them concatenated when the caller closes. - func collect(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func collect( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// Streams back messages as they are received in an input stream. - func update(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func update( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Conformance to `GRPCCore.RegistrableRPCService`. @@ -107,32 +119,44 @@ extension Echo_Echo.StreamingServiceProtocol { forMethod: Echo_Echo.Method.Get.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.get(request: request) + handler: { request, context in + try await self.get( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Echo_Echo.Method.Expand.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.expand(request: request) + handler: { request, context in + try await self.expand( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Echo_Echo.Method.Collect.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.collect(request: request) + handler: { request, context in + try await self.collect( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Echo_Echo.Method.Update.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.update(request: request) + handler: { request, context in + try await self.update( + request: request, + context: context + ) } ) } @@ -141,33 +165,63 @@ extension Echo_Echo.StreamingServiceProtocol { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) internal protocol Echo_EchoServiceProtocol: Echo_Echo.StreamingServiceProtocol { /// Immediately returns an echo of a request. - func get(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func get( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single /// Splits a request into words and returns each word in a stream of messages. - func expand(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Stream + func expand( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// Collects a stream of messages and returns them concatenated when the caller closes. - func collect(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Single + func collect( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single /// Streams back messages as they are received in an input stream. - func update(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func update( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Partial conformance to `Echo_EchoStreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension Echo_Echo.ServiceProtocol { - internal func get(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.get(request: GRPCCore.ServerRequest.Single(stream: request)) + internal func get( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.get( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } - internal func expand(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.expand(request: GRPCCore.ServerRequest.Single(stream: request)) + internal func expand( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.expand( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return response } - internal func collect(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.collect(request: request) + internal func collect( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.collect( + request: request, + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } } diff --git a/Examples/v2/echo/Subcommands/Serve.swift b/Examples/v2/echo/Subcommands/Serve.swift index d03adbbe8..5bfa1772f 100644 --- a/Examples/v2/echo/Subcommands/Serve.swift +++ b/Examples/v2/echo/Subcommands/Serve.swift @@ -47,13 +47,15 @@ struct Serve: AsyncParsableCommand { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) struct EchoService: Echo_EchoServiceProtocol { func get( - request: ServerRequest.Single + request: ServerRequest.Single, + context: ServerContext ) async throws -> ServerResponse.Single { return ServerResponse.Single(message: .with { $0.text = request.message.text }) } func collect( - request: ServerRequest.Stream + request: ServerRequest.Stream, + context: ServerContext ) async throws -> ServerResponse.Single { let messages = try await request.messages.reduce(into: []) { $0.append($1.text) } let joined = messages.joined(separator: " ") @@ -61,7 +63,8 @@ struct EchoService: Echo_EchoServiceProtocol { } func expand( - request: ServerRequest.Single + request: ServerRequest.Single, + context: ServerContext ) async throws -> ServerResponse.Stream { return ServerResponse.Stream { writer in let parts = request.message.text.split(separator: " ") @@ -72,7 +75,8 @@ struct EchoService: Echo_EchoServiceProtocol { } func update( - request: ServerRequest.Stream + request: ServerRequest.Stream, + context: ServerContext ) async throws -> ServerResponse.Stream { return ServerResponse.Stream { writer in for try await message in request.messages { diff --git a/Examples/v2/hello-world/Generated/helloworld.grpc.swift b/Examples/v2/hello-world/Generated/helloworld.grpc.swift index 0336b83ca..8044411e5 100644 --- a/Examples/v2/hello-world/Generated/helloworld.grpc.swift +++ b/Examples/v2/hello-world/Generated/helloworld.grpc.swift @@ -60,7 +60,10 @@ extension GRPCCore.ServiceDescriptor { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) internal protocol Helloworld_GreeterStreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// Sends a greeting - func sayHello(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func sayHello( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Conformance to `GRPCCore.RegistrableRPCService`. @@ -72,8 +75,11 @@ extension Helloworld_Greeter.StreamingServiceProtocol { forMethod: Helloworld_Greeter.Method.SayHello.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.sayHello(request: request) + handler: { request, context in + try await self.sayHello( + request: request, + context: context + ) } ) } @@ -83,14 +89,23 @@ extension Helloworld_Greeter.StreamingServiceProtocol { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) internal protocol Helloworld_GreeterServiceProtocol: Helloworld_Greeter.StreamingServiceProtocol { /// Sends a greeting - func sayHello(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func sayHello( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single } /// Partial conformance to `Helloworld_GreeterStreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension Helloworld_Greeter.ServiceProtocol { - internal func sayHello(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.sayHello(request: GRPCCore.ServerRequest.Single(stream: request)) + internal func sayHello( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.sayHello( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } } diff --git a/Examples/v2/hello-world/Subcommands/Serve.swift b/Examples/v2/hello-world/Subcommands/Serve.swift index fe4e462ea..a9dd178ec 100644 --- a/Examples/v2/hello-world/Subcommands/Serve.swift +++ b/Examples/v2/hello-world/Subcommands/Serve.swift @@ -46,7 +46,8 @@ struct Serve: AsyncParsableCommand { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) struct Greeter: Helloworld_GreeterServiceProtocol { func sayHello( - request: ServerRequest.Single + request: ServerRequest.Single, + context: ServerContext ) async throws -> ServerResponse.Single { var reply = Helloworld_HelloReply() let recipient = request.message.name.isEmpty ? "stranger" : request.message.name diff --git a/Examples/v2/route-guide/Generated/route_guide.grpc.swift b/Examples/v2/route-guide/Generated/route_guide.grpc.swift index cf7cb7182..6a89ed2a3 100644 --- a/Examples/v2/route-guide/Generated/route_guide.grpc.swift +++ b/Examples/v2/route-guide/Generated/route_guide.grpc.swift @@ -92,7 +92,10 @@ internal protocol Routeguide_RouteGuideStreamingServiceProtocol: GRPCCore.Regist /// /// A feature with an empty name is returned if there's no feature at the given /// position. - func getFeature(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func getFeature( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// A server-to-client streaming RPC. /// @@ -100,19 +103,28 @@ internal protocol Routeguide_RouteGuideStreamingServiceProtocol: GRPCCore.Regist /// streamed rather than returned at once (e.g. in a response message with a /// repeated field), as the rectangle may cover a large area and contain a /// huge number of features. - func listFeatures(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func listFeatures( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// A client-to-server streaming RPC. /// /// Accepts a stream of Points on a route being traversed, returning a /// RouteSummary when traversal is completed. - func recordRoute(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func recordRoute( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// A Bidirectional streaming RPC. /// /// Accepts a stream of RouteNotes sent while a route is being traversed, /// while receiving other RouteNotes (e.g. from other users). - func routeChat(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func routeChat( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Conformance to `GRPCCore.RegistrableRPCService`. @@ -124,32 +136,44 @@ extension Routeguide_RouteGuide.StreamingServiceProtocol { forMethod: Routeguide_RouteGuide.Method.GetFeature.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.getFeature(request: request) + handler: { request, context in + try await self.getFeature( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Routeguide_RouteGuide.Method.ListFeatures.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.listFeatures(request: request) + handler: { request, context in + try await self.listFeatures( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Routeguide_RouteGuide.Method.RecordRoute.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.recordRoute(request: request) + handler: { request, context in + try await self.recordRoute( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Routeguide_RouteGuide.Method.RouteChat.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.routeChat(request: request) + handler: { request, context in + try await self.routeChat( + request: request, + context: context + ) } ) } @@ -164,7 +188,10 @@ internal protocol Routeguide_RouteGuideServiceProtocol: Routeguide_RouteGuide.St /// /// A feature with an empty name is returned if there's no feature at the given /// position. - func getFeature(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func getFeature( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single /// A server-to-client streaming RPC. /// @@ -172,36 +199,63 @@ internal protocol Routeguide_RouteGuideServiceProtocol: Routeguide_RouteGuide.St /// streamed rather than returned at once (e.g. in a response message with a /// repeated field), as the rectangle may cover a large area and contain a /// huge number of features. - func listFeatures(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Stream + func listFeatures( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// A client-to-server streaming RPC. /// /// Accepts a stream of Points on a route being traversed, returning a /// RouteSummary when traversal is completed. - func recordRoute(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Single + func recordRoute( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single /// A Bidirectional streaming RPC. /// /// Accepts a stream of RouteNotes sent while a route is being traversed, /// while receiving other RouteNotes (e.g. from other users). - func routeChat(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func routeChat( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Partial conformance to `Routeguide_RouteGuideStreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension Routeguide_RouteGuide.ServiceProtocol { - internal func getFeature(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.getFeature(request: GRPCCore.ServerRequest.Single(stream: request)) + internal func getFeature( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.getFeature( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } - internal func listFeatures(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.listFeatures(request: GRPCCore.ServerRequest.Single(stream: request)) + internal func listFeatures( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.listFeatures( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return response } - internal func recordRoute(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.recordRoute(request: request) + internal func recordRoute( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.recordRoute( + request: request, + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } } diff --git a/Examples/v2/route-guide/Subcommands/Serve.swift b/Examples/v2/route-guide/Subcommands/Serve.swift index 8de97671e..f9b942876 100644 --- a/Examples/v2/route-guide/Subcommands/Serve.swift +++ b/Examples/v2/route-guide/Subcommands/Serve.swift @@ -103,7 +103,8 @@ struct RouteGuideService { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { func getFeature( - request: ServerRequest.Single + request: ServerRequest.Single, + context: ServerContext ) async throws -> ServerResponse.Single { let feature = self.findFeature( latitude: request.message.latitude, @@ -126,7 +127,8 @@ extension RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { } func listFeatures( - request: ServerRequest.Single + request: ServerRequest.Single, + context: ServerContext ) async throws -> ServerResponse.Stream { return ServerResponse.Stream { writer in let featuresWithinBounds = self.features.filter { feature in @@ -139,7 +141,8 @@ extension RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { } func recordRoute( - request: ServerRequest.Stream + request: ServerRequest.Stream, + context: ServerContext ) async throws -> ServerResponse.Single { let startTime = ContinuousClock.now var pointsVisited = 0 @@ -173,7 +176,8 @@ extension RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { } func routeChat( - request: ServerRequest.Stream + request: ServerRequest.Stream, + context: ServerContext ) async throws -> ServerResponse.Stream { return ServerResponse.Stream { writer in for try await note in request.messages { diff --git a/Sources/GRPCCodeGen/Internal/Translator/IDLToStructuredSwiftTranslator.swift b/Sources/GRPCCodeGen/Internal/Translator/IDLToStructuredSwiftTranslator.swift index 99c9acfaa..4e49e2828 100644 --- a/Sources/GRPCCodeGen/Internal/Translator/IDLToStructuredSwiftTranslator.swift +++ b/Sources/GRPCCodeGen/Internal/Translator/IDLToStructuredSwiftTranslator.swift @@ -26,14 +26,46 @@ struct IDLToStructuredSwiftTranslator: Translator { server: Bool ) throws -> StructuredSwiftRepresentation { try self.validateInput(codeGenerationRequest) + + var codeBlocks = [CodeBlock]() + let typealiasTranslator = TypealiasTranslator( client: client, server: server, accessLevel: accessLevel ) + codeBlocks.append(contentsOf: try typealiasTranslator.translate(from: codeGenerationRequest)) - let topComment = Comment.preFormatted(codeGenerationRequest.leadingTrivia) + if server { + let serverCodeTranslator = ServerCodeTranslator(accessLevel: accessLevel) + codeBlocks.append(contentsOf: try serverCodeTranslator.translate(from: codeGenerationRequest)) + } + if client { + let clientCodeTranslator = ClientCodeTranslator(accessLevel: accessLevel) + codeBlocks.append(contentsOf: try clientCodeTranslator.translate(from: codeGenerationRequest)) + } + + let fileDescription = FileDescription( + topComment: .preFormatted(codeGenerationRequest.leadingTrivia), + imports: try self.makeImports( + dependencies: codeGenerationRequest.dependencies, + accessLevel: accessLevel, + accessLevelOnImports: accessLevelOnImports + ), + codeBlocks: codeBlocks + ) + + let fileName = String(codeGenerationRequest.fileName.split(separator: ".")[0]) + let file = NamedFileDescription(name: fileName, contents: fileDescription) + return StructuredSwiftRepresentation(file: file) + } + + private func makeImports( + dependencies: [CodeGenerationRequest.Dependency], + accessLevel: SourceGenerator.Configuration.AccessLevel, + accessLevelOnImports: Bool + ) throws -> [ImportDescription] { var imports: [ImportDescription] = [] imports.append( ImportDescription( @@ -42,7 +74,7 @@ struct IDLToStructuredSwiftTranslator: Translator { ) ) - for dependency in codeGenerationRequest.dependencies { + for dependency in dependencies { let importDescription = try self.translateImport( dependency: dependency, accessLevelOnImports: accessLevelOnImports @@ -50,33 +82,7 @@ struct IDLToStructuredSwiftTranslator: Translator { imports.append(importDescription) } - var codeBlocks = [CodeBlock]() - codeBlocks.append( - contentsOf: try typealiasTranslator.translate(from: codeGenerationRequest) - ) - - if server { - let serverCodeTranslator = ServerCodeTranslator(accessLevel: accessLevel) - codeBlocks.append( - contentsOf: try serverCodeTranslator.translate(from: codeGenerationRequest) - ) - } - - if client { - let clientCodeTranslator = ClientCodeTranslator(accessLevel: accessLevel) - codeBlocks.append( - contentsOf: try clientCodeTranslator.translate(from: codeGenerationRequest) - ) - } - - let fileDescription = FileDescription( - topComment: topComment, - imports: imports, - codeBlocks: codeBlocks - ) - let fileName = String(codeGenerationRequest.fileName.split(separator: ".")[0]) - let file = NamedFileDescription(name: fileName, contents: fileDescription) - return StructuredSwiftRepresentation(file: file) + return imports } } diff --git a/Sources/GRPCCodeGen/Internal/Translator/ServerCodeTranslator.swift b/Sources/GRPCCodeGen/Internal/Translator/ServerCodeTranslator.swift index 313c3410e..f9f88dd95 100644 --- a/Sources/GRPCCodeGen/Internal/Translator/ServerCodeTranslator.swift +++ b/Sources/GRPCCodeGen/Internal/Translator/ServerCodeTranslator.swift @@ -150,7 +150,8 @@ extension ServerCodeTranslator { wrapper: .member(["GRPCCore", "ServerRequest", "Stream"]), wrapped: .member(method.inputType) ) - ) + ), + .init(label: "context", type: .member(["GRPCCore", "ServerContext"])), ], keywords: [.async, .throws], returnType: .identifierType( @@ -229,30 +230,27 @@ extension ServerCodeTranslator { ) -> [FunctionArgumentDescription] { var arguments = [FunctionArgumentDescription]() arguments.append( - .init( + FunctionArgumentDescription( label: "forMethod", - expression: .identifierPattern( - self.methodDescriptorPath(for: method, service: service) - ) + expression: .identifierPattern(self.methodDescriptorPath(for: method, service: service)) ) ) arguments.append( - .init( + FunctionArgumentDescription( label: "deserializer", expression: .identifierPattern(codeGenerationRequest.lookupDeserializer(method.inputType)) ) ) arguments.append( - .init( + FunctionArgumentDescription( label: "serializer", - expression: - .identifierPattern(codeGenerationRequest.lookupSerializer(method.outputType)) + expression: .identifierPattern(codeGenerationRequest.lookupSerializer(method.outputType)) ) ) - let getFunctionCall = Expression.functionCall( + let rpcFunctionCall = Expression.functionCall( calledExpression: .memberAccess( MemberAccessDescription( left: .identifierPattern("self"), @@ -260,20 +258,24 @@ extension ServerCodeTranslator { ) ), arguments: [ - FunctionArgumentDescription(label: "request", expression: .identifierPattern("request")) + FunctionArgumentDescription(label: "request", expression: .identifierPattern("request")), + FunctionArgumentDescription(label: "context", expression: .identifierPattern("context")), ] ) let handlerClosureBody = Expression.unaryKeyword( kind: .try, - expression: .unaryKeyword(kind: .await, expression: getFunctionCall) + expression: .unaryKeyword(kind: .await, expression: rpcFunctionCall) ) arguments.append( - .init( + FunctionArgumentDescription( label: "handler", expression: .closureInvocation( - .init(argumentNames: ["request"], body: [.expression(handlerClosureBody)]) + ClosureInvocationDescription( + argumentNames: ["request", "context"], + body: [.expression(handlerClosureBody)] + ) ) ) ) @@ -325,7 +327,8 @@ extension ServerCodeTranslator { wrapper: .member(["GRPCCore", "ServerRequest", inputStreaming]), wrapped: .member(method.inputType) ) - ) + ), + .init(label: "context", type: .member(["GRPCCore", "ServerContext"])), ], keywords: [.async, .throws], returnType: .identifierType( @@ -409,7 +412,10 @@ extension ServerCodeTranslator { right: method.name.generatedLowerCase ) ), - arguments: [FunctionArgumentDescription(label: "request", expression: serverRequest)] + arguments: [ + FunctionArgumentDescription(label: "request", expression: serverRequest), + FunctionArgumentDescription(label: "context", expression: .identifier(.pattern("context"))), + ] ) let responseValue = Expression.unaryKeyword( diff --git a/Sources/GRPCCore/Call/Server/Internal/ServerRPCExecutor.swift b/Sources/GRPCCore/Call/Server/Internal/ServerRPCExecutor.swift index 74f657884..a67bfbe37 100644 --- a/Sources/GRPCCore/Call/Server/Internal/ServerRPCExecutor.swift +++ b/Sources/GRPCCore/Call/Server/Internal/ServerRPCExecutor.swift @@ -20,6 +20,7 @@ struct ServerRPCExecutor { /// Executes an RPC using the provided handler. /// /// - Parameters: + /// - context: The context for the RPC. /// - stream: The accepted stream to execute the RPC on. /// - deserializer: A deserializer for messages received from the client. /// - serializer: A serializer for messages to send to the client. @@ -27,6 +28,7 @@ struct ServerRPCExecutor { /// - handler: A handler which turns the request into a response. @inlinable static func execute( + context: ServerContext, stream: RPCStream< RPCAsyncSequence, RPCWriter.Closable @@ -35,7 +37,8 @@ struct ServerRPCExecutor { serializer: some MessageSerializer, interceptors: [any ServerInterceptor], handler: @Sendable @escaping ( - _ request: ServerRequest.Stream + _ request: ServerRequest.Stream, + _ context: ServerContext ) async throws -> ServerResponse.Stream ) async { // Wait for the first request part from the transport. @@ -44,7 +47,7 @@ struct ServerRPCExecutor { switch firstPart { case .process(let metadata, let inbound): await Self._execute( - method: stream.descriptor, + context: context, metadata: metadata, inbound: inbound, outbound: stream.outbound, @@ -64,7 +67,7 @@ struct ServerRPCExecutor { @inlinable static func _execute( - method: MethodDescriptor, + context: ServerContext, metadata: Metadata, inbound: UnsafeTransfer.AsyncIterator>, outbound: RPCWriter.Closable, @@ -72,13 +75,14 @@ struct ServerRPCExecutor { serializer: some MessageSerializer, interceptors: [any ServerInterceptor], handler: @escaping @Sendable ( - _ request: ServerRequest.Stream + _ request: ServerRequest.Stream, + _ context: ServerContext ) async throws -> ServerResponse.Stream ) async { if let timeout = metadata.timeout { await Self._processRPCWithTimeout( timeout: timeout, - method: method, + context: context, metadata: metadata, inbound: inbound, outbound: outbound, @@ -89,7 +93,7 @@ struct ServerRPCExecutor { ) } else { await Self._processRPC( - method: method, + context: context, metadata: metadata, inbound: inbound, outbound: outbound, @@ -104,7 +108,7 @@ struct ServerRPCExecutor { @inlinable static func _processRPCWithTimeout( timeout: Duration, - method: MethodDescriptor, + context: ServerContext, metadata: Metadata, inbound: UnsafeTransfer.AsyncIterator>, outbound: RPCWriter.Closable, @@ -112,7 +116,8 @@ struct ServerRPCExecutor { serializer: some MessageSerializer, interceptors: [any ServerInterceptor], handler: @escaping @Sendable ( - ServerRequest.Stream + _ request: ServerRequest.Stream, + _ context: ServerContext ) async throws -> ServerResponse.Stream ) async { await withTaskGroup(of: ServerExecutorTask.self) { group in @@ -125,7 +130,7 @@ struct ServerRPCExecutor { group.addTask { await Self._processRPC( - method: method, + context: context, metadata: metadata, inbound: inbound, outbound: outbound, @@ -157,7 +162,7 @@ struct ServerRPCExecutor { @inlinable static func _processRPC( - method: MethodDescriptor, + context: ServerContext, metadata: Metadata, inbound: UnsafeTransfer.AsyncIterator>, outbound: RPCWriter.Closable, @@ -165,7 +170,8 @@ struct ServerRPCExecutor { serializer: some MessageSerializer, interceptors: [any ServerInterceptor], handler: @escaping @Sendable ( - ServerRequest.Stream + _ request: ServerRequest.Stream, + _ context: ServerContext ) async throws -> ServerResponse.Stream ) async { let messages = UncheckedAsyncIteratorSequence(inbound.wrappedValue).map { part in @@ -190,10 +196,10 @@ struct ServerRPCExecutor { metadata: metadata, messages: RPCAsyncSequence(wrapping: messages) ), - context: ServerInterceptorContext(descriptor: method), + context: context, interceptors: interceptors - ) { request, _ in - try await handler(request) + ) { request, context in + try await handler(request, context) } }.castError(to: RPCError.self) { error in RPCError(code: .unknown, message: "Service method threw an unknown error.", cause: error) @@ -295,11 +301,11 @@ extension ServerRPCExecutor { @inlinable static func _intercept( request: ServerRequest.Stream, - context: ServerInterceptorContext, + context: ServerContext, interceptors: [any ServerInterceptor], finally: @escaping @Sendable ( _ request: ServerRequest.Stream, - _ context: ServerInterceptorContext + _ context: ServerContext ) async throws -> ServerResponse.Stream ) async throws -> ServerResponse.Stream { return try await self._intercept( @@ -313,11 +319,11 @@ extension ServerRPCExecutor { @inlinable static func _intercept( request: ServerRequest.Stream, - context: ServerInterceptorContext, + context: ServerContext, iterator: Array.Iterator, finally: @escaping @Sendable ( _ request: ServerRequest.Stream, - _ context: ServerInterceptorContext + _ context: ServerContext ) async throws -> ServerResponse.Stream ) async throws -> ServerResponse.Stream { var iterator = iterator diff --git a/Sources/GRPCCore/Call/Server/RPCRouter.swift b/Sources/GRPCCore/Call/Server/RPCRouter.swift index b6ae3f074..bc2f58fef 100644 --- a/Sources/GRPCCore/Call/Server/RPCRouter.swift +++ b/Sources/GRPCCore/Call/Server/RPCRouter.swift @@ -43,6 +43,7 @@ public struct RPCRouter: Sendable { RPCAsyncSequence, RPCWriter.Closable >, + _ context: ServerContext, _ interceptors: [any ServerInterceptor] ) async -> Void @@ -52,11 +53,13 @@ public struct RPCRouter: Sendable { deserializer: some MessageDeserializer, serializer: some MessageSerializer, handler: @Sendable @escaping ( - _ request: ServerRequest.Stream + _ request: ServerRequest.Stream, + _ context: ServerContext ) async throws -> ServerResponse.Stream ) { - self._fn = { stream, interceptors in + self._fn = { stream, context, interceptors in await ServerRPCExecutor.execute( + context: context, stream: stream, deserializer: deserializer, serializer: serializer, @@ -72,9 +75,10 @@ public struct RPCRouter: Sendable { RPCAsyncSequence, RPCWriter.Closable >, + context: ServerContext, interceptors: [any ServerInterceptor] ) async { - await self._fn(stream, interceptors) + await self._fn(stream, context, interceptors) } } @@ -119,7 +123,8 @@ public struct RPCRouter: Sendable { deserializer: some MessageDeserializer, serializer: some MessageSerializer, handler: @Sendable @escaping ( - _ request: ServerRequest.Stream + _ request: ServerRequest.Stream, + _ context: ServerContext ) async throws -> ServerResponse.Stream ) { self.handlers[descriptor] = RPCHandler( @@ -147,10 +152,11 @@ extension RPCRouter { RPCAsyncSequence, RPCWriter.Closable >, + context: ServerContext, interceptors: [any ServerInterceptor] ) async { if let handler = self.handlers[stream.descriptor] { - await handler.handle(stream: stream, interceptors: interceptors) + await handler.handle(stream: stream, context: context, interceptors: interceptors) } else { // If this throws then the stream must be closed which we can't do anything about, so ignore // any error. diff --git a/Sources/GRPCCore/Call/Server/ServerContext.swift b/Sources/GRPCCore/Call/Server/ServerContext.swift new file mode 100644 index 000000000..a11f09acb --- /dev/null +++ b/Sources/GRPCCore/Call/Server/ServerContext.swift @@ -0,0 +1,26 @@ +/* + * Copyright 2024, gRPC Authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// Additional information about an RPC handled by a server. +public struct ServerContext: Sendable { + /// A description of the method being called. + public var descriptor: MethodDescriptor + + /// Create a new server context. + public init(descriptor: MethodDescriptor) { + self.descriptor = descriptor + } +} diff --git a/Sources/GRPCCore/Call/Server/ServerInterceptor.swift b/Sources/GRPCCore/Call/Server/ServerInterceptor.swift index 69981b529..2243fe8f2 100644 --- a/Sources/GRPCCore/Call/Server/ServerInterceptor.swift +++ b/Sources/GRPCCore/Call/Server/ServerInterceptor.swift @@ -60,7 +60,7 @@ /// } /// ``` /// -/// For server-side interceptors see ``ClientInterceptor``. +/// For client-side interceptors see ``ClientInterceptor``. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) public protocol ServerInterceptor: Sendable { /// Intercept a request object. @@ -74,21 +74,10 @@ public protocol ServerInterceptor: Sendable { /// - Returns: A response object. func intercept( request: ServerRequest.Stream, - context: ServerInterceptorContext, + context: ServerContext, next: @Sendable ( _ request: ServerRequest.Stream, - _ context: ServerInterceptorContext + _ context: ServerContext ) async throws -> ServerResponse.Stream ) async throws -> ServerResponse.Stream } - -/// A context passed to client interceptors containing additional information about the RPC. -public struct ServerInterceptorContext: Sendable { - /// A description of the method being called. - public var descriptor: MethodDescriptor - - /// Create a new client interceptor context. - public init(descriptor: MethodDescriptor) { - self.descriptor = descriptor - } -} diff --git a/Sources/GRPCCore/GRPCServer.swift b/Sources/GRPCCore/GRPCServer.swift index e5d7fa8ee..da46e2db8 100644 --- a/Sources/GRPCCore/GRPCServer.swift +++ b/Sources/GRPCCore/GRPCServer.swift @@ -206,8 +206,8 @@ public final class GRPCServer: Sendable { } do { - try await transport.listen { stream in - await self.router.handle(stream: stream, interceptors: self.interceptors) + try await transport.listen { stream, context in + await self.router.handle(stream: stream, context: context, interceptors: self.interceptors) } } catch { throw RuntimeError( diff --git a/Sources/GRPCCore/Transport/ServerTransport.swift b/Sources/GRPCCore/Transport/ServerTransport.swift index abb4b8c90..79c5c0fc6 100644 --- a/Sources/GRPCCore/Transport/ServerTransport.swift +++ b/Sources/GRPCCore/Transport/ServerTransport.swift @@ -29,9 +29,12 @@ public protocol ServerTransport: Sendable { /// You can call ``beginGracefulShutdown()`` to stop the transport from accepting new streams. Existing /// streams must be allowed to complete naturally. However, transports may also enforce a grace /// period after which any open streams may be cancelled. You can also cancel the task running - /// ``listen(_:)`` to abruptly close connections and streams. + /// ``listen(streamHandler:)`` to abruptly close connections and streams. func listen( - _ streamHandler: @escaping @Sendable (RPCStream) async -> Void + streamHandler: @escaping @Sendable ( + _ stream: RPCStream, + _ context: ServerContext + ) async -> Void ) async throws /// Indicates to the transport that no new streams should be accepted. diff --git a/Sources/GRPCHTTP2Core/Server/CommonHTTP2ServerTransport.swift b/Sources/GRPCHTTP2Core/Server/CommonHTTP2ServerTransport.swift index a900b5402..769db9bf7 100644 --- a/Sources/GRPCHTTP2Core/Server/CommonHTTP2ServerTransport.swift +++ b/Sources/GRPCHTTP2Core/Server/CommonHTTP2ServerTransport.swift @@ -144,7 +144,10 @@ package final class CommonHTTP2ServerTransport< } package func listen( - _ streamHandler: @escaping @Sendable (RPCStream) async -> Void + streamHandler: @escaping @Sendable ( + _ stream: RPCStream, + _ context: ServerContext + ) async -> Void ) async throws { defer { switch self.listeningAddressState.withLock({ $0.close() }) { @@ -192,7 +195,10 @@ package final class CommonHTTP2ServerTransport< private func handleConnection( _ connection: NIOAsyncChannel, multiplexer: ChannelPipeline.SynchronousOperations.HTTP2StreamMultiplexer, - streamHandler: @escaping @Sendable (RPCStream) async -> Void + streamHandler: @escaping @Sendable ( + _ stream: RPCStream, + _ context: ServerContext + ) async -> Void ) async throws { try await connection.executeThenClose { inbound, _ in await withDiscardingTaskGroup { group in @@ -220,7 +226,10 @@ package final class CommonHTTP2ServerTransport< private func handleStream( _ stream: NIOAsyncChannel, - handler streamHandler: @escaping @Sendable (RPCStream) async -> Void, + handler streamHandler: @escaping @Sendable ( + _ stream: RPCStream, + _ context: ServerContext + ) async -> Void, descriptor: EventLoopFuture ) async { // It's okay to ignore these errors: @@ -244,7 +253,8 @@ package final class CommonHTTP2ServerTransport< ) ) - await streamHandler(rpcStream) + let context = ServerContext(descriptor: descriptor) + await streamHandler(rpcStream, context) } } diff --git a/Sources/GRPCHTTP2TransportNIOPosix/HTTP2ServerTransport+Posix.swift b/Sources/GRPCHTTP2TransportNIOPosix/HTTP2ServerTransport+Posix.swift index d7bda6350..0aa14aefa 100644 --- a/Sources/GRPCHTTP2TransportNIOPosix/HTTP2ServerTransport+Posix.swift +++ b/Sources/GRPCHTTP2TransportNIOPosix/HTTP2ServerTransport+Posix.swift @@ -163,9 +163,12 @@ extension HTTP2ServerTransport { } public func listen( - _ streamHandler: @escaping @Sendable (RPCStream) async -> Void + streamHandler: @escaping @Sendable ( + _ stream: RPCStream, + _ context: ServerContext + ) async -> Void ) async throws { - try await self.underlyingTransport.listen(streamHandler) + try await self.underlyingTransport.listen(streamHandler: streamHandler) } public func beginGracefulShutdown() { diff --git a/Sources/GRPCHTTP2TransportNIOTransportServices/HTTP2ServerTransport+TransportServices.swift b/Sources/GRPCHTTP2TransportNIOTransportServices/HTTP2ServerTransport+TransportServices.swift index 94628e215..31fd3a312 100644 --- a/Sources/GRPCHTTP2TransportNIOTransportServices/HTTP2ServerTransport+TransportServices.swift +++ b/Sources/GRPCHTTP2TransportNIOTransportServices/HTTP2ServerTransport+TransportServices.swift @@ -117,9 +117,12 @@ extension HTTP2ServerTransport { } public func listen( - _ streamHandler: @escaping @Sendable (RPCStream) async -> Void + streamHandler: @escaping @Sendable ( + _ stream: RPCStream, + _ context: ServerContext + ) async -> Void ) async throws { - try await self.underlyingTransport.listen(streamHandler) + try await self.underlyingTransport.listen(streamHandler: streamHandler) } public func beginGracefulShutdown() { diff --git a/Sources/GRPCInProcessTransport/InProcessServerTransport.swift b/Sources/GRPCInProcessTransport/InProcessServerTransport.swift index 4c627037f..2bb2ed57d 100644 --- a/Sources/GRPCInProcessTransport/InProcessServerTransport.swift +++ b/Sources/GRPCInProcessTransport/InProcessServerTransport.swift @@ -56,12 +56,16 @@ public struct InProcessServerTransport: ServerTransport, Sendable { } public func listen( - _ streamHandler: @escaping @Sendable (RPCStream) async -> Void + streamHandler: @escaping @Sendable ( + _ stream: RPCStream, + _ context: ServerContext + ) async -> Void ) async throws { await withDiscardingTaskGroup { group in for await stream in self.newStreams { group.addTask { - await streamHandler(stream) + let context = ServerContext(descriptor: stream.descriptor) + await streamHandler(stream, context) } } } diff --git a/Sources/GRPCInterceptors/ServerTracingInterceptor.swift b/Sources/GRPCInterceptors/ServerTracingInterceptor.swift index 5a568e425..a2ebe456c 100644 --- a/Sources/GRPCInterceptors/ServerTracingInterceptor.swift +++ b/Sources/GRPCInterceptors/ServerTracingInterceptor.swift @@ -44,8 +44,8 @@ public struct ServerTracingInterceptor: ServerInterceptor { /// that has been configured when bootstrapping `swift-distributed-tracing` in your application. public func intercept( request: ServerRequest.Stream, - context: ServerInterceptorContext, - next: @Sendable (ServerRequest.Stream, ServerInterceptorContext) async throws -> + context: ServerContext, + next: @Sendable (ServerRequest.Stream, ServerContext) async throws -> ServerResponse.Stream ) async throws -> ServerResponse.Stream where Input: Sendable, Output: Sendable { var serviceContext = ServiceContext.topLevel diff --git a/Sources/InteroperabilityTests/Generated/test.grpc.swift b/Sources/InteroperabilityTests/Generated/test.grpc.swift index 5fed75d22..bbdbf3e49 100644 --- a/Sources/InteroperabilityTests/Generated/test.grpc.swift +++ b/Sources/InteroperabilityTests/Generated/test.grpc.swift @@ -200,38 +200,62 @@ extension GRPCCore.ServiceDescriptor { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) public protocol Grpc_Testing_TestServiceStreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// One empty request followed by one empty response. - func emptyCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func emptyCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// One request followed by one response. - func unaryCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func unaryCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// One request followed by one response. Response has cache control /// headers set such that a caching HTTP proxy (such as GFE) can /// satisfy subsequent requests. - func cacheableUnaryCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func cacheableUnaryCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// One request followed by a sequence of responses (streamed download). /// The server returns the payload with client desired type and sizes. - func streamingOutputCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func streamingOutputCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// A sequence of requests followed by one response (streamed upload). /// The server returns the aggregated size of client payload as the result. - func streamingInputCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func streamingInputCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// A sequence of requests with each request served by the server immediately. /// As one request could lead to multiple responses, this interface /// demonstrates the idea of full duplexing. - func fullDuplexCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func fullDuplexCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// A sequence of requests followed by a sequence of responses. /// The server buffers all the client requests and then serves them in order. A /// stream of responses are returned to the client when the server starts with /// first request. - func halfDuplexCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func halfDuplexCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// The test server will not implement this method. It will be used /// to test the behavior when clients call unimplemented methods. - func unimplementedCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func unimplementedCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Conformance to `GRPCCore.RegistrableRPCService`. @@ -243,64 +267,88 @@ extension Grpc_Testing_TestService.StreamingServiceProtocol { forMethod: Grpc_Testing_TestService.Method.EmptyCall.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.emptyCall(request: request) + handler: { request, context in + try await self.emptyCall( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Grpc_Testing_TestService.Method.UnaryCall.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.unaryCall(request: request) + handler: { request, context in + try await self.unaryCall( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Grpc_Testing_TestService.Method.CacheableUnaryCall.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.cacheableUnaryCall(request: request) + handler: { request, context in + try await self.cacheableUnaryCall( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Grpc_Testing_TestService.Method.StreamingOutputCall.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.streamingOutputCall(request: request) + handler: { request, context in + try await self.streamingOutputCall( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Grpc_Testing_TestService.Method.StreamingInputCall.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.streamingInputCall(request: request) + handler: { request, context in + try await self.streamingInputCall( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Grpc_Testing_TestService.Method.FullDuplexCall.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.fullDuplexCall(request: request) + handler: { request, context in + try await self.fullDuplexCall( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Grpc_Testing_TestService.Method.HalfDuplexCall.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.halfDuplexCall(request: request) + handler: { request, context in + try await self.halfDuplexCall( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Grpc_Testing_TestService.Method.UnimplementedCall.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.unimplementedCall(request: request) + handler: { request, context in + try await self.unimplementedCall( + request: request, + context: context + ) } ) } @@ -311,70 +359,130 @@ extension Grpc_Testing_TestService.StreamingServiceProtocol { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) public protocol Grpc_Testing_TestServiceServiceProtocol: Grpc_Testing_TestService.StreamingServiceProtocol { /// One empty request followed by one empty response. - func emptyCall(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func emptyCall( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single /// One request followed by one response. - func unaryCall(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func unaryCall( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single /// One request followed by one response. Response has cache control /// headers set such that a caching HTTP proxy (such as GFE) can /// satisfy subsequent requests. - func cacheableUnaryCall(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func cacheableUnaryCall( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single /// One request followed by a sequence of responses (streamed download). /// The server returns the payload with client desired type and sizes. - func streamingOutputCall(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Stream + func streamingOutputCall( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// A sequence of requests followed by one response (streamed upload). /// The server returns the aggregated size of client payload as the result. - func streamingInputCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Single + func streamingInputCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single /// A sequence of requests with each request served by the server immediately. /// As one request could lead to multiple responses, this interface /// demonstrates the idea of full duplexing. - func fullDuplexCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func fullDuplexCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// A sequence of requests followed by a sequence of responses. /// The server buffers all the client requests and then serves them in order. A /// stream of responses are returned to the client when the server starts with /// first request. - func halfDuplexCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func halfDuplexCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// The test server will not implement this method. It will be used /// to test the behavior when clients call unimplemented methods. - func unimplementedCall(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func unimplementedCall( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single } /// Partial conformance to `Grpc_Testing_TestServiceStreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension Grpc_Testing_TestService.ServiceProtocol { - public func emptyCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.emptyCall(request: GRPCCore.ServerRequest.Single(stream: request)) + public func emptyCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.emptyCall( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } - public func unaryCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.unaryCall(request: GRPCCore.ServerRequest.Single(stream: request)) + public func unaryCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.unaryCall( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } - public func cacheableUnaryCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.cacheableUnaryCall(request: GRPCCore.ServerRequest.Single(stream: request)) + public func cacheableUnaryCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.cacheableUnaryCall( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } - public func streamingOutputCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.streamingOutputCall(request: GRPCCore.ServerRequest.Single(stream: request)) + public func streamingOutputCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.streamingOutputCall( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return response } - public func streamingInputCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.streamingInputCall(request: request) + public func streamingInputCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.streamingInputCall( + request: request, + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } - public func unimplementedCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.unimplementedCall(request: GRPCCore.ServerRequest.Single(stream: request)) + public func unimplementedCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.unimplementedCall( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } } @@ -384,7 +492,10 @@ extension Grpc_Testing_TestService.ServiceProtocol { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) public protocol Grpc_Testing_UnimplementedServiceStreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// A call that no server should implement - func unimplementedCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func unimplementedCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Conformance to `GRPCCore.RegistrableRPCService`. @@ -396,8 +507,11 @@ extension Grpc_Testing_UnimplementedService.StreamingServiceProtocol { forMethod: Grpc_Testing_UnimplementedService.Method.UnimplementedCall.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.unimplementedCall(request: request) + handler: { request, context in + try await self.unimplementedCall( + request: request, + context: context + ) } ) } @@ -408,14 +522,23 @@ extension Grpc_Testing_UnimplementedService.StreamingServiceProtocol { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) public protocol Grpc_Testing_UnimplementedServiceServiceProtocol: Grpc_Testing_UnimplementedService.StreamingServiceProtocol { /// A call that no server should implement - func unimplementedCall(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func unimplementedCall( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single } /// Partial conformance to `Grpc_Testing_UnimplementedServiceStreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension Grpc_Testing_UnimplementedService.ServiceProtocol { - public func unimplementedCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.unimplementedCall(request: GRPCCore.ServerRequest.Single(stream: request)) + public func unimplementedCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.unimplementedCall( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } } @@ -423,9 +546,15 @@ extension Grpc_Testing_UnimplementedService.ServiceProtocol { /// A service used to control reconnect server. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) public protocol Grpc_Testing_ReconnectServiceStreamingServiceProtocol: GRPCCore.RegistrableRPCService { - func start(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func start( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream - func stop(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func stop( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Conformance to `GRPCCore.RegistrableRPCService`. @@ -437,16 +566,22 @@ extension Grpc_Testing_ReconnectService.StreamingServiceProtocol { forMethod: Grpc_Testing_ReconnectService.Method.Start.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.start(request: request) + handler: { request, context in + try await self.start( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Grpc_Testing_ReconnectService.Method.Stop.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.stop(request: request) + handler: { request, context in + try await self.stop( + request: request, + context: context + ) } ) } @@ -455,21 +590,39 @@ extension Grpc_Testing_ReconnectService.StreamingServiceProtocol { /// A service used to control reconnect server. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) public protocol Grpc_Testing_ReconnectServiceServiceProtocol: Grpc_Testing_ReconnectService.StreamingServiceProtocol { - func start(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func start( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single - func stop(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func stop( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single } /// Partial conformance to `Grpc_Testing_ReconnectServiceStreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension Grpc_Testing_ReconnectService.ServiceProtocol { - public func start(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.start(request: GRPCCore.ServerRequest.Single(stream: request)) + public func start( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.start( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } - public func stop(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.stop(request: GRPCCore.ServerRequest.Single(stream: request)) + public func stop( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.stop( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } } diff --git a/Sources/InteroperabilityTests/TestService.swift b/Sources/InteroperabilityTests/TestService.swift index 02c27c1f3..f4c79b784 100644 --- a/Sources/InteroperabilityTests/TestService.swift +++ b/Sources/InteroperabilityTests/TestService.swift @@ -22,16 +22,16 @@ public struct TestService: Grpc_Testing_TestService.ServiceProtocol { public init() {} public func unimplementedCall( - request: ServerRequest.Single - ) async throws - -> ServerResponse.Single - { + request: ServerRequest.Single, + context: ServerContext + ) async throws -> ServerResponse.Single { throw RPCError(code: .unimplemented, message: "The RPC is not implemented.") } /// Server implements `emptyCall` which immediately returns the empty message. public func emptyCall( - request: ServerRequest.Single + request: ServerRequest.Single, + context: ServerContext ) async throws -> ServerResponse.Single { let message = Grpc_Testing_Empty() let (initialMetadata, trailingMetadata) = request.metadata.makeInitialAndTrailingMetadata() @@ -49,7 +49,8 @@ public struct TestService: Grpc_Testing_TestService.ServiceProtocol { /// If the server does not support the `responseType`, then it should fail the RPC with /// `INVALID_ARGUMENT`. public func unaryCall( - request: ServerRequest.Single + request: ServerRequest.Single, + context: ServerContext ) async throws -> ServerResponse.Single { // We can't validate messages at the wire-encoding layer (i.e. where the compression byte is // set), so we have to check via the encoding header. Note that it is possible for the header @@ -108,10 +109,9 @@ public struct TestService: Grpc_Testing_TestService.ServiceProtocol { /// headers such that the response can be cached by proxies in the response path. Server should /// be behind a caching proxy for this test to pass. Currently we set the max-age to 60 seconds. public func cacheableUnaryCall( - request: ServerRequest.Single - ) async throws - -> ServerResponse.Single - { + request: ServerRequest.Single, + context: ServerContext + ) async throws -> ServerResponse.Single { throw RPCError(code: .unimplemented, message: "The RPC is not implemented.") } @@ -121,12 +121,9 @@ public struct TestService: Grpc_Testing_TestService.ServiceProtocol { /// bytes, as specified by its respective `ResponseParameter`. After sending all responses, it /// closes with OK. public func streamingOutputCall( - request: ServerRequest.Single< - Grpc_Testing_StreamingOutputCallRequest - > - ) async throws - -> ServerResponse.Stream - { + request: ServerRequest.Single, + context: ServerContext + ) async throws -> ServerResponse.Stream { let (initialMetadata, trailingMetadata) = request.metadata.makeInitialAndTrailingMetadata() return ServerResponse.Stream(metadata: initialMetadata) { writer in for responseParameter in request.message.responseParameters { @@ -147,10 +144,9 @@ public struct TestService: Grpc_Testing_TestService.ServiceProtocol { /// `StreamingInputCallResponse` where `aggregatedPayloadSize` is the sum of all request payload /// bodies received. public func streamingInputCall( - request: ServerRequest.Stream - ) async throws - -> ServerResponse.Single - { + request: ServerRequest.Stream, + context: ServerContext + ) async throws -> ServerResponse.Single { let isRequestCompressed = request.metadata["grpc-encoding"].filter({ $0 != "identity" }).count > 0 var aggregatedPayloadSize = 0 @@ -187,10 +183,9 @@ public struct TestService: Grpc_Testing_TestService.ServiceProtocol { /// of size `ResponseParameter.size` bytes, as specified by its respective `ResponseParameter`s. /// After receiving half close and sending all responses, it closes with OK. public func fullDuplexCall( - request: ServerRequest.Stream - ) async throws - -> ServerResponse.Stream - { + request: ServerRequest.Stream, + context: ServerContext + ) async throws -> ServerResponse.Stream { let (initialMetadata, trailingMetadata) = request.metadata.makeInitialAndTrailingMetadata() return ServerResponse.Stream(metadata: initialMetadata) { writer in for try await message in request.messages { @@ -226,10 +221,9 @@ public struct TestService: Grpc_Testing_TestService.ServiceProtocol { /// /// See: https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md public func halfDuplexCall( - request: ServerRequest.Stream - ) async throws - -> ServerResponse.Stream - { + request: ServerRequest.Stream, + context: ServerContext + ) async throws -> ServerResponse.Stream { throw RPCError(code: .unimplemented, message: "The RPC is not implemented.") } } diff --git a/Sources/Services/Health/Generated/health.grpc.swift b/Sources/Services/Health/Generated/health.grpc.swift index 16f73d5b3..a2f625c74 100644 --- a/Sources/Services/Health/Generated/health.grpc.swift +++ b/Sources/Services/Health/Generated/health.grpc.swift @@ -82,7 +82,10 @@ package protocol Grpc_Health_V1_HealthStreamingServiceProtocol: GRPCCore.Registr /// server unhealthy if they do not receive a timely response. /// /// Check implementations should be idempotent and side effect free. - func check(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func check( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// Performs a watch for the serving status of the requested service. /// The server will immediately send back a message indicating the current @@ -99,7 +102,10 @@ package protocol Grpc_Health_V1_HealthStreamingServiceProtocol: GRPCCore.Registr /// should assume this method is not supported and should not retry the /// call. If the call terminates with any other status (including OK), /// clients should retry the call with appropriate exponential backoff. - func watch(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func watch( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Conformance to `GRPCCore.RegistrableRPCService`. @@ -111,16 +117,22 @@ extension Grpc_Health_V1_Health.StreamingServiceProtocol { forMethod: Grpc_Health_V1_Health.Method.Check.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.check(request: request) + handler: { request, context in + try await self.check( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Grpc_Health_V1_Health.Method.Watch.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.watch(request: request) + handler: { request, context in + try await self.watch( + request: request, + context: context + ) } ) } @@ -140,7 +152,10 @@ package protocol Grpc_Health_V1_HealthServiceProtocol: Grpc_Health_V1_Health.Str /// server unhealthy if they do not receive a timely response. /// /// Check implementations should be idempotent and side effect free. - func check(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func check( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single /// Performs a watch for the serving status of the requested service. /// The server will immediately send back a message indicating the current @@ -157,19 +172,34 @@ package protocol Grpc_Health_V1_HealthServiceProtocol: Grpc_Health_V1_Health.Str /// should assume this method is not supported and should not retry the /// call. If the call terminates with any other status (including OK), /// clients should retry the call with appropriate exponential backoff. - func watch(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Stream + func watch( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Partial conformance to `Grpc_Health_V1_HealthStreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension Grpc_Health_V1_Health.ServiceProtocol { - package func check(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.check(request: GRPCCore.ServerRequest.Single(stream: request)) + package func check( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.check( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } - package func watch(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.watch(request: GRPCCore.ServerRequest.Single(stream: request)) + package func watch( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.watch( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return response } } diff --git a/Sources/Services/Health/HealthService.swift b/Sources/Services/Health/HealthService.swift index 72f70e064..362e707f2 100644 --- a/Sources/Services/Health/HealthService.swift +++ b/Sources/Services/Health/HealthService.swift @@ -22,7 +22,8 @@ internal struct HealthService: Grpc_Health_V1_HealthServiceProtocol { private let state = HealthService.State() func check( - request: ServerRequest.Single + request: ServerRequest.Single, + context: ServerContext ) async throws -> ServerResponse.Single { let service = request.message.service @@ -37,16 +38,15 @@ internal struct HealthService: Grpc_Health_V1_HealthServiceProtocol { } func watch( - request: ServerRequest.Single + request: ServerRequest.Single, + context: ServerContext ) async -> ServerResponse.Stream { let service = request.message.service let statuses = AsyncStream.makeStream(of: Grpc_Health_V1_HealthCheckResponse.ServingStatus.self) self.state.addContinuation(statuses.continuation, forService: service) - return ServerResponse.Stream( - of: Grpc_Health_V1_HealthCheckResponse.self - ) { writer in + return ServerResponse.Stream(of: Grpc_Health_V1_HealthCheckResponse.self) { writer in var response = Grpc_Health_V1_HealthCheckResponse() for await status in statuses.stream { diff --git a/Sources/performance-worker/BenchmarkService.swift b/Sources/performance-worker/BenchmarkService.swift index 11631eaaf..b73d46534 100644 --- a/Sources/performance-worker/BenchmarkService.swift +++ b/Sources/performance-worker/BenchmarkService.swift @@ -27,7 +27,8 @@ final class BenchmarkService: Grpc_Testing_BenchmarkService.ServiceProtocol { /// One request followed by one response. /// The server returns a client payload with the size requested by the client. func unaryCall( - request: ServerRequest.Single + request: ServerRequest.Single, + context: ServerContext ) async throws -> ServerResponse.Single { // Throw an error if the status is not `ok`. Otherwise, an `ok` status is automatically sent // if the request is successful. @@ -47,7 +48,8 @@ final class BenchmarkService: Grpc_Testing_BenchmarkService.ServiceProtocol { /// Repeated sequence of one request followed by one response. /// The server returns a payload with the size requested by the client for each received message. func streamingCall( - request: ServerRequest.Stream + request: ServerRequest.Stream, + context: ServerContext ) async throws -> ServerResponse.Stream { return ServerResponse.Stream { writer in for try await message in request.messages { @@ -71,7 +73,8 @@ final class BenchmarkService: Grpc_Testing_BenchmarkService.ServiceProtocol { /// Single-sided unbounded streaming from client to server. /// The server returns a payload with the size requested by the client once the client does WritesDone. func streamingFromClient( - request: ServerRequest.Stream + request: ServerRequest.Stream, + context: ServerContext ) async throws -> ServerResponse.Single { var responseSize = 0 for try await message in request.messages { @@ -93,7 +96,8 @@ final class BenchmarkService: Grpc_Testing_BenchmarkService.ServiceProtocol { /// Single-sided unbounded streaming from server to client. /// The server repeatedly returns a payload with the size requested by the client. func streamingFromServer( - request: ServerRequest.Single + request: ServerRequest.Single, + context: ServerContext ) async throws -> ServerResponse.Stream { if request.message.responseStatus.isInitialized { try self.checkOkStatus(request.message.responseStatus) @@ -116,7 +120,8 @@ final class BenchmarkService: Grpc_Testing_BenchmarkService.ServiceProtocol { /// Two-sided unbounded streaming between server to client. /// Both sides send the content of their own choice to the other. func streamingBothWays( - request: ServerRequest.Stream + request: ServerRequest.Stream, + context: ServerContext ) async throws -> ServerResponse.Stream { // The 100 size is used by the other implementations as well. // We are using the same canned response size for all responses diff --git a/Sources/performance-worker/Generated/grpc_testing_benchmark_service.grpc.swift b/Sources/performance-worker/Generated/grpc_testing_benchmark_service.grpc.swift index 663922d0b..d8b4cdc6b 100644 --- a/Sources/performance-worker/Generated/grpc_testing_benchmark_service.grpc.swift +++ b/Sources/performance-worker/Generated/grpc_testing_benchmark_service.grpc.swift @@ -99,24 +99,39 @@ extension GRPCCore.ServiceDescriptor { internal protocol Grpc_Testing_BenchmarkServiceStreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// One request followed by one response. /// The server returns the client payload as-is. - func unaryCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func unaryCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// Repeated sequence of one request followed by one response. /// Should be called streaming ping-pong /// The server returns the client payload as-is on each response - func streamingCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func streamingCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// Single-sided unbounded streaming from client to server /// The server returns the client payload as-is once the client does WritesDone - func streamingFromClient(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func streamingFromClient( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// Single-sided unbounded streaming from server to client /// The server repeatedly returns the client payload as-is - func streamingFromServer(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func streamingFromServer( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// Two-sided unbounded streaming between server to client /// Both sides send the content of their own choice to the other - func streamingBothWays(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func streamingBothWays( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Conformance to `GRPCCore.RegistrableRPCService`. @@ -128,40 +143,55 @@ extension Grpc_Testing_BenchmarkService.StreamingServiceProtocol { forMethod: Grpc_Testing_BenchmarkService.Method.UnaryCall.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.unaryCall(request: request) + handler: { request, context in + try await self.unaryCall( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Grpc_Testing_BenchmarkService.Method.StreamingCall.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.streamingCall(request: request) + handler: { request, context in + try await self.streamingCall( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Grpc_Testing_BenchmarkService.Method.StreamingFromClient.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.streamingFromClient(request: request) + handler: { request, context in + try await self.streamingFromClient( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Grpc_Testing_BenchmarkService.Method.StreamingFromServer.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.streamingFromServer(request: request) + handler: { request, context in + try await self.streamingFromServer( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Grpc_Testing_BenchmarkService.Method.StreamingBothWays.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.streamingBothWays(request: request) + handler: { request, context in + try await self.streamingBothWays( + request: request, + context: context + ) } ) } @@ -171,41 +201,74 @@ extension Grpc_Testing_BenchmarkService.StreamingServiceProtocol { internal protocol Grpc_Testing_BenchmarkServiceServiceProtocol: Grpc_Testing_BenchmarkService.StreamingServiceProtocol { /// One request followed by one response. /// The server returns the client payload as-is. - func unaryCall(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func unaryCall( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single /// Repeated sequence of one request followed by one response. /// Should be called streaming ping-pong /// The server returns the client payload as-is on each response - func streamingCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func streamingCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// Single-sided unbounded streaming from client to server /// The server returns the client payload as-is once the client does WritesDone - func streamingFromClient(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Single + func streamingFromClient( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single /// Single-sided unbounded streaming from server to client /// The server repeatedly returns the client payload as-is - func streamingFromServer(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Stream + func streamingFromServer( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// Two-sided unbounded streaming between server to client /// Both sides send the content of their own choice to the other - func streamingBothWays(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func streamingBothWays( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Partial conformance to `Grpc_Testing_BenchmarkServiceStreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension Grpc_Testing_BenchmarkService.ServiceProtocol { - internal func unaryCall(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.unaryCall(request: GRPCCore.ServerRequest.Single(stream: request)) + internal func unaryCall( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.unaryCall( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } - internal func streamingFromClient(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.streamingFromClient(request: request) + internal func streamingFromClient( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.streamingFromClient( + request: request, + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } - internal func streamingFromServer(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.streamingFromServer(request: GRPCCore.ServerRequest.Single(stream: request)) + internal func streamingFromServer( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.streamingFromServer( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return response } } diff --git a/Sources/performance-worker/Generated/grpc_testing_worker_service.grpc.swift b/Sources/performance-worker/Generated/grpc_testing_worker_service.grpc.swift index f1637253f..58bad0ad0 100644 --- a/Sources/performance-worker/Generated/grpc_testing_worker_service.grpc.swift +++ b/Sources/performance-worker/Generated/grpc_testing_worker_service.grpc.swift @@ -90,7 +90,10 @@ internal protocol Grpc_Testing_WorkerServiceStreamingServiceProtocol: GRPCCore.R /// stats. Closing the stream will initiate shutdown of the test server /// and once the shutdown has finished, the OK status is sent to terminate /// this RPC. - func runServer(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func runServer( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// Start client with specified workload. /// First request sent specifies the ClientConfig followed by ClientStatus @@ -98,13 +101,22 @@ internal protocol Grpc_Testing_WorkerServiceStreamingServiceProtocol: GRPCCore.R /// stats. Closing the stream will initiate shutdown of the test client /// and once the shutdown has finished, the OK status is sent to terminate /// this RPC. - func runClient(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func runClient( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// Just return the core count - unary call - func coreCount(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func coreCount( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// Quit this worker - func quitWorker(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func quitWorker( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Conformance to `GRPCCore.RegistrableRPCService`. @@ -116,32 +128,44 @@ extension Grpc_Testing_WorkerService.StreamingServiceProtocol { forMethod: Grpc_Testing_WorkerService.Method.RunServer.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.runServer(request: request) + handler: { request, context in + try await self.runServer( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Grpc_Testing_WorkerService.Method.RunClient.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.runClient(request: request) + handler: { request, context in + try await self.runClient( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Grpc_Testing_WorkerService.Method.CoreCount.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.coreCount(request: request) + handler: { request, context in + try await self.coreCount( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Grpc_Testing_WorkerService.Method.QuitWorker.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.quitWorker(request: request) + handler: { request, context in + try await self.quitWorker( + request: request, + context: context + ) } ) } @@ -155,7 +179,10 @@ internal protocol Grpc_Testing_WorkerServiceServiceProtocol: Grpc_Testing_Worker /// stats. Closing the stream will initiate shutdown of the test server /// and once the shutdown has finished, the OK status is sent to terminate /// this RPC. - func runServer(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func runServer( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// Start client with specified workload. /// First request sent specifies the ClientConfig followed by ClientStatus @@ -163,25 +190,46 @@ internal protocol Grpc_Testing_WorkerServiceServiceProtocol: Grpc_Testing_Worker /// stats. Closing the stream will initiate shutdown of the test client /// and once the shutdown has finished, the OK status is sent to terminate /// this RPC. - func runClient(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func runClient( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// Just return the core count - unary call - func coreCount(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func coreCount( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single /// Quit this worker - func quitWorker(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func quitWorker( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single } /// Partial conformance to `Grpc_Testing_WorkerServiceStreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension Grpc_Testing_WorkerService.ServiceProtocol { - internal func coreCount(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.coreCount(request: GRPCCore.ServerRequest.Single(stream: request)) + internal func coreCount( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.coreCount( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } - internal func quitWorker(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.quitWorker(request: GRPCCore.ServerRequest.Single(stream: request)) + internal func quitWorker( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.quitWorker( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } } \ No newline at end of file diff --git a/Sources/performance-worker/WorkerService.swift b/Sources/performance-worker/WorkerService.swift index 2864fc405..945dca3a7 100644 --- a/Sources/performance-worker/WorkerService.swift +++ b/Sources/performance-worker/WorkerService.swift @@ -225,7 +225,8 @@ final class WorkerService: Sendable { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension WorkerService: Grpc_Testing_WorkerService.ServiceProtocol { func quitWorker( - request: ServerRequest.Single + request: ServerRequest.Single, + context: ServerContext ) async throws -> ServerResponse.Single { let onQuit = self.state.withLockedValue { $0.quit() } @@ -246,7 +247,8 @@ extension WorkerService: Grpc_Testing_WorkerService.ServiceProtocol { } func coreCount( - request: ServerRequest.Single + request: ServerRequest.Single, + context: ServerContext ) async throws -> ServerResponse.Single { let coreCount = System.coreCount return ServerResponse.Single( @@ -257,7 +259,8 @@ extension WorkerService: Grpc_Testing_WorkerService.ServiceProtocol { } func runServer( - request: ServerRequest.Stream + request: ServerRequest.Stream, + context: ServerContext ) async throws -> ServerResponse.Stream { return ServerResponse.Stream { writer in try await withThrowingTaskGroup(of: Void.self) { group in @@ -328,7 +331,8 @@ extension WorkerService: Grpc_Testing_WorkerService.ServiceProtocol { } func runClient( - request: ServerRequest.Stream + request: ServerRequest.Stream, + context: ServerContext ) async throws -> ServerResponse.Stream { return ServerResponse.Stream { writer in try await withThrowingTaskGroup(of: Void.self) { group in diff --git a/Tests/GRPCCodeGenTests/Internal/Translator/ServerCodeTranslatorSnippetBasedTests.swift b/Tests/GRPCCodeGenTests/Internal/Translator/ServerCodeTranslatorSnippetBasedTests.swift index ea8ff3186..8ec1c8015 100644 --- a/Tests/GRPCCodeGenTests/Internal/Translator/ServerCodeTranslatorSnippetBasedTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/Translator/ServerCodeTranslatorSnippetBasedTests.swift @@ -54,7 +54,10 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) public protocol NamespaceA_ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// Documentation for unaryMethod - func unary(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func unary( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Conformance to `GRPCCore.RegistrableRPCService`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) @@ -65,8 +68,11 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { forMethod: NamespaceA_ServiceA.Method.Unary.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.unary(request: request) + handler: { request, context in + try await self.unary( + request: request, + context: context + ) } ) } @@ -75,13 +81,22 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) public protocol NamespaceA_ServiceAServiceProtocol: NamespaceA_ServiceA.StreamingServiceProtocol { /// Documentation for unaryMethod - func unary(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func unary( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single } /// Partial conformance to `NamespaceA_ServiceAStreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension NamespaceA_ServiceA.ServiceProtocol { - public func unary(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.unary(request: GRPCCore.ServerRequest.Single(stream: request)) + public func unary( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.unary( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } } @@ -123,7 +138,10 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) package protocol NamespaceA_ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// Documentation for inputStreamingMethod - func inputStreaming(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func inputStreaming( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Conformance to `GRPCCore.RegistrableRPCService`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) @@ -134,8 +152,11 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { forMethod: NamespaceA_ServiceA.Method.InputStreaming.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.inputStreaming(request: request) + handler: { request, context in + try await self.inputStreaming( + request: request, + context: context + ) } ) } @@ -144,13 +165,22 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) package protocol NamespaceA_ServiceAServiceProtocol: NamespaceA_ServiceA.StreamingServiceProtocol { /// Documentation for inputStreamingMethod - func inputStreaming(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Single + func inputStreaming( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single } /// Partial conformance to `NamespaceA_ServiceAStreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension NamespaceA_ServiceA.ServiceProtocol { - package func inputStreaming(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.inputStreaming(request: request) + package func inputStreaming( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.inputStreaming( + request: request, + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } } @@ -196,7 +226,10 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) public protocol NamespaceA_ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// Documentation for outputStreamingMethod - func outputStreaming(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func outputStreaming( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Conformance to `GRPCCore.RegistrableRPCService`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) @@ -207,8 +240,11 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { forMethod: NamespaceA_ServiceA.Method.OutputStreaming.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.outputStreaming(request: request) + handler: { request, context in + try await self.outputStreaming( + request: request, + context: context + ) } ) } @@ -217,13 +253,22 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) public protocol NamespaceA_ServiceAServiceProtocol: NamespaceA_ServiceA.StreamingServiceProtocol { /// Documentation for outputStreamingMethod - func outputStreaming(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Stream + func outputStreaming( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Partial conformance to `NamespaceA_ServiceAStreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension NamespaceA_ServiceA.ServiceProtocol { - public func outputStreaming(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.outputStreaming(request: GRPCCore.ServerRequest.Single(stream: request)) + public func outputStreaming( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.outputStreaming( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return response } } @@ -269,7 +314,10 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) package protocol NamespaceA_ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// Documentation for bidirectionalStreamingMethod - func bidirectionalStreaming(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func bidirectionalStreaming( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Conformance to `GRPCCore.RegistrableRPCService`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) @@ -280,8 +328,11 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { forMethod: NamespaceA_ServiceA.Method.BidirectionalStreaming.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.bidirectionalStreaming(request: request) + handler: { request, context in + try await self.bidirectionalStreaming( + request: request, + context: context + ) } ) } @@ -290,7 +341,10 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) package protocol NamespaceA_ServiceAServiceProtocol: NamespaceA_ServiceA.StreamingServiceProtocol { /// Documentation for bidirectionalStreamingMethod - func bidirectionalStreaming(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func bidirectionalStreaming( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Partial conformance to `NamespaceA_ServiceAStreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) @@ -350,10 +404,16 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) internal protocol NamespaceA_ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// Documentation for inputStreamingMethod - func inputStreaming(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func inputStreaming( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream /// Documentation for outputStreamingMethod - func outputStreaming(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func outputStreaming( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Conformance to `GRPCCore.RegistrableRPCService`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) @@ -364,16 +424,22 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { forMethod: NamespaceA_ServiceA.Method.InputStreaming.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.inputStreaming(request: request) + handler: { request, context in + try await self.inputStreaming( + request: request, + context: context + ) } ) router.registerHandler( forMethod: NamespaceA_ServiceA.Method.OutputStreaming.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.outputStreaming(request: request) + handler: { request, context in + try await self.outputStreaming( + request: request, + context: context + ) } ) } @@ -382,21 +448,39 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) internal protocol NamespaceA_ServiceAServiceProtocol: NamespaceA_ServiceA.StreamingServiceProtocol { /// Documentation for inputStreamingMethod - func inputStreaming(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Single + func inputStreaming( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single /// Documentation for outputStreamingMethod - func outputStreaming(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Stream + func outputStreaming( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Partial conformance to `NamespaceA_ServiceAStreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension NamespaceA_ServiceA.ServiceProtocol { - internal func inputStreaming(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.inputStreaming(request: request) + internal func inputStreaming( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.inputStreaming( + request: request, + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } - internal func outputStreaming(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.outputStreaming(request: GRPCCore.ServerRequest.Single(stream: request)) + internal func outputStreaming( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.outputStreaming( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return response } } @@ -434,7 +518,10 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) internal protocol ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// Documentation for MethodA - func methodA(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func methodA( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Conformance to `GRPCCore.RegistrableRPCService`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) @@ -445,8 +532,11 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { forMethod: ServiceA.Method.MethodA.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.methodA(request: request) + handler: { request, context in + try await self.methodA( + request: request, + context: context + ) } ) } @@ -455,13 +545,22 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) internal protocol ServiceAServiceProtocol: ServiceA.StreamingServiceProtocol { /// Documentation for MethodA - func methodA(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func methodA( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single } /// Partial conformance to `ServiceAStreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension ServiceA.ServiceProtocol { - internal func methodA(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.methodA(request: GRPCCore.ServerRequest.Single(stream: request)) + internal func methodA( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.methodA( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } } diff --git a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness.swift b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness.swift index d9bf10f23..06f200ae6 100644 --- a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness.swift +++ b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness.swift @@ -121,7 +121,7 @@ struct ClientRPCExecutorTestHarness { ) async throws { try await withThrowingTaskGroup(of: Void.self) { group in group.addTask { - try await self.serverTransport.listen { stream in + try await self.serverTransport.listen { stream, context in try? await self.server.handle(stream: stream) } } diff --git a/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTestSupport/ServerRPCExecutorTestHarness.swift b/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTestSupport/ServerRPCExecutorTestHarness.swift index 274913ab8..8d7e0a543 100644 --- a/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTestSupport/ServerRPCExecutorTestHarness.swift +++ b/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTestSupport/ServerRPCExecutorTestHarness.swift @@ -93,16 +93,20 @@ struct ServerRPCExecutorTestHarness { } group.addTask { + let context = ServerContext(descriptor: MethodDescriptor(service: "foo", method: "bar")) await ServerRPCExecutor.execute( + context: context, stream: RPCStream( - descriptor: MethodDescriptor(service: "foo", method: "bar"), + descriptor: context.descriptor, inbound: RPCAsyncSequence(wrapping: input.stream), outbound: RPCWriter.Closable(wrapping: output.continuation) ), deserializer: deserializer, serializer: serializer, interceptors: self.interceptors, - handler: { try await handler.handle($0) } + handler: { stream, context in + try await handler.handle(stream) + } ) } diff --git a/Tests/GRPCCoreTests/Call/Server/RPCRouterTests.swift b/Tests/GRPCCoreTests/Call/Server/RPCRouterTests.swift index c1d9a023f..86fe1bd1e 100644 --- a/Tests/GRPCCoreTests/Call/Server/RPCRouterTests.swift +++ b/Tests/GRPCCoreTests/Call/Server/RPCRouterTests.swift @@ -34,7 +34,7 @@ final class RPCRouterTests: XCTestCase { forMethod: method, deserializer: IdentityDeserializer(), serializer: IdentitySerializer() - ) { _ in + ) { _, _ in throw RPCError(code: .failedPrecondition, message: "Shouldn't be called") } @@ -50,7 +50,7 @@ final class RPCRouterTests: XCTestCase { forMethod: method, deserializer: IdentityDeserializer(), serializer: IdentitySerializer() - ) { _ in + ) { _, _ in throw RPCError(code: .failedPrecondition, message: "Shouldn't be called") } diff --git a/Tests/GRPCCoreTests/Test Utilities/Call/Server/ServerInterceptors.swift b/Tests/GRPCCoreTests/Test Utilities/Call/Server/ServerInterceptors.swift index 97c68aba9..9a3dc96c7 100644 --- a/Tests/GRPCCoreTests/Test Utilities/Call/Server/ServerInterceptors.swift +++ b/Tests/GRPCCoreTests/Test Utilities/Call/Server/ServerInterceptors.swift @@ -50,10 +50,10 @@ struct RejectAllServerInterceptor: ServerInterceptor { func intercept( request: ServerRequest.Stream, - context: ServerInterceptorContext, + context: ServerContext, next: @Sendable ( ServerRequest.Stream, - ServerInterceptorContext + ServerContext ) async throws -> ServerResponse.Stream ) async throws -> ServerResponse.Stream { if self.throw { @@ -75,10 +75,10 @@ struct RequestCountingServerInterceptor: ServerInterceptor { func intercept( request: ServerRequest.Stream, - context: ServerInterceptorContext, + context: ServerContext, next: @Sendable ( ServerRequest.Stream, - ServerInterceptorContext + ServerContext ) async throws -> ServerResponse.Stream ) async throws -> ServerResponse.Stream { self.counter.increment() diff --git a/Tests/GRPCCoreTests/Test Utilities/Services/BinaryEcho.swift b/Tests/GRPCCoreTests/Test Utilities/Services/BinaryEcho.swift index f1b462376..e5438c550 100644 --- a/Tests/GRPCCoreTests/Test Utilities/Services/BinaryEcho.swift +++ b/Tests/GRPCCoreTests/Test Utilities/Services/BinaryEcho.swift @@ -61,7 +61,7 @@ struct BinaryEcho: RegistrableRPCService { forMethod: Methods.get, deserializer: deserializer, serializer: serializer - ) { streamRequest in + ) { streamRequest, context in let singleRequest = try await ServerRequest.Single(stream: streamRequest) let singleResponse = try await self.get(singleRequest) return ServerResponse.Stream(single: singleResponse) @@ -71,7 +71,7 @@ struct BinaryEcho: RegistrableRPCService { forMethod: Methods.collect, deserializer: deserializer, serializer: serializer - ) { streamRequest in + ) { streamRequest, context in let singleResponse = try await self.collect(streamRequest) return ServerResponse.Stream(single: singleResponse) } @@ -80,7 +80,7 @@ struct BinaryEcho: RegistrableRPCService { forMethod: Methods.expand, deserializer: deserializer, serializer: serializer - ) { streamRequest in + ) { streamRequest, context in let singleRequest = try await ServerRequest.Single(stream: streamRequest) let streamResponse = try await self.expand(singleRequest) return streamResponse @@ -90,7 +90,7 @@ struct BinaryEcho: RegistrableRPCService { forMethod: Methods.update, deserializer: deserializer, serializer: serializer - ) { streamRequest in + ) { streamRequest, context in let streamResponse = try await self.update(streamRequest) return streamResponse } diff --git a/Tests/GRPCCoreTests/Test Utilities/Transport/AnyTransport.swift b/Tests/GRPCCoreTests/Test Utilities/Transport/AnyTransport.swift index b5953dd3a..086cf2127 100644 --- a/Tests/GRPCCoreTests/Test Utilities/Transport/AnyTransport.swift +++ b/Tests/GRPCCoreTests/Test Utilities/Transport/AnyTransport.swift @@ -88,17 +88,23 @@ struct AnyServerTransport: ServerTransport, Sendable { private let _listen: @Sendable ( - @escaping @Sendable (RPCStream) async -> Void + @escaping @Sendable ( + _ stream: RPCStream, + _ context: ServerContext + ) async -> Void ) async throws -> Void private let _stopListening: @Sendable () -> Void init(wrapping transport: Transport) { - self._listen = { streamHandler in try await transport.listen(streamHandler) } + self._listen = { streamHandler in try await transport.listen(streamHandler: streamHandler) } self._stopListening = { transport.beginGracefulShutdown() } } func listen( - _ streamHandler: @escaping @Sendable (RPCStream) async -> Void + streamHandler: @escaping @Sendable ( + _ stream: RPCStream, + _ context: ServerContext + ) async -> Void ) async throws { try await self._listen(streamHandler) } diff --git a/Tests/GRPCCoreTests/Test Utilities/Transport/StreamCountingTransport.swift b/Tests/GRPCCoreTests/Test Utilities/Transport/StreamCountingTransport.swift index cd3df5af5..9bbed93a4 100644 --- a/Tests/GRPCCoreTests/Test Utilities/Transport/StreamCountingTransport.swift +++ b/Tests/GRPCCoreTests/Test Utilities/Transport/StreamCountingTransport.swift @@ -96,11 +96,14 @@ struct StreamCountingServerTransport: ServerTransport, Sendable { } func listen( - _ streamHandler: @escaping @Sendable (RPCStream) async -> Void + streamHandler: @escaping @Sendable ( + _ stream: RPCStream, + _ context: ServerContext + ) async -> Void ) async throws { - try await self.transport.listen { stream in + try await self.transport.listen { stream, context in self._acceptedStreams.increment() - await streamHandler(stream) + await streamHandler(stream, context) } } diff --git a/Tests/GRPCCoreTests/Test Utilities/Transport/ThrowingTransport.swift b/Tests/GRPCCoreTests/Test Utilities/Transport/ThrowingTransport.swift index b9b1b6d80..b9c9b97e6 100644 --- a/Tests/GRPCCoreTests/Test Utilities/Transport/ThrowingTransport.swift +++ b/Tests/GRPCCoreTests/Test Utilities/Transport/ThrowingTransport.swift @@ -53,7 +53,12 @@ struct ThrowOnStreamCreationTransport: ClientTransport { @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) struct ThrowOnRunServerTransport: ServerTransport { - func listen(_ streamHandler: (RPCStream) async -> Void) async throws { + func listen( + streamHandler: ( + _ stream: RPCStream, + _ context: ServerContext + ) async -> Void + ) async throws { throw RPCError( code: .unavailable, message: "The '\(type(of: self))' transport is never available." @@ -74,7 +79,10 @@ struct ThrowOnSignalServerTransport: ServerTransport { } func listen( - _ streamHandler: (GRPCCore.RPCStream) async -> Void + streamHandler: ( + _ stream: RPCStream, + _ context: ServerContext + ) async -> Void ) async throws { for await _ in self.signal {} diff --git a/Tests/GRPCHTTP2TransportTests/ControlService.swift b/Tests/GRPCHTTP2TransportTests/ControlService.swift index dfb83b132..9139d9a42 100644 --- a/Tests/GRPCHTTP2TransportTests/ControlService.swift +++ b/Tests/GRPCHTTP2TransportTests/ControlService.swift @@ -21,25 +21,29 @@ import struct Foundation.Data @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) struct ControlService: ControlStreamingServiceProtocol { func unary( - request: ServerRequest.Stream + request: ServerRequest.Stream, + context: ServerContext ) async throws -> ServerResponse.Stream { try await self.handle(request: request) } func serverStream( - request: ServerRequest.Stream + request: ServerRequest.Stream, + context: ServerContext ) async throws -> ServerResponse.Stream { try await self.handle(request: request) } func clientStream( - request: ServerRequest.Stream + request: ServerRequest.Stream, + context: ServerContext ) async throws -> ServerResponse.Stream { try await self.handle(request: request) } func bidiStream( - request: ServerRequest.Stream + request: ServerRequest.Stream, + context: ServerContext ) async throws -> ServerResponse.Stream { try await self.handle(request: request) } diff --git a/Tests/GRPCHTTP2TransportTests/Generated/control.grpc.swift b/Tests/GRPCHTTP2TransportTests/Generated/control.grpc.swift index ebd5c8e76..8833dc856 100644 --- a/Tests/GRPCHTTP2TransportTests/Generated/control.grpc.swift +++ b/Tests/GRPCHTTP2TransportTests/Generated/control.grpc.swift @@ -90,13 +90,25 @@ extension GRPCCore.ServiceDescriptor { /// the output. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) internal protocol ControlStreamingServiceProtocol: GRPCCore.RegistrableRPCService { - func unary(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func unary( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream - func serverStream(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func serverStream( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream - func clientStream(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func clientStream( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream - func bidiStream(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func bidiStream( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Conformance to `GRPCCore.RegistrableRPCService`. @@ -108,32 +120,44 @@ extension Control.StreamingServiceProtocol { forMethod: Control.Method.Unary.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.unary(request: request) + handler: { request, context in + try await self.unary( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Control.Method.ServerStream.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.serverStream(request: request) + handler: { request, context in + try await self.serverStream( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Control.Method.ClientStream.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.clientStream(request: request) + handler: { request, context in + try await self.clientStream( + request: request, + context: context + ) } ) router.registerHandler( forMethod: Control.Method.BidiStream.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.bidiStream(request: request) + handler: { request, context in + try await self.bidiStream( + request: request, + context: context + ) } ) } @@ -145,30 +169,60 @@ extension Control.StreamingServiceProtocol { /// the output. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) internal protocol ControlServiceProtocol: Control.StreamingServiceProtocol { - func unary(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func unary( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single - func serverStream(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Stream + func serverStream( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream - func clientStream(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Single + func clientStream( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single - func bidiStream(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func bidiStream( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Partial conformance to `ControlStreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension Control.ServiceProtocol { - internal func unary(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.unary(request: GRPCCore.ServerRequest.Single(stream: request)) + internal func unary( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.unary( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } - internal func serverStream(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.serverStream(request: GRPCCore.ServerRequest.Single(stream: request)) + internal func serverStream( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.serverStream( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return response } - internal func clientStream(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.clientStream(request: request) + internal func clientStream( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.clientStream( + request: request, + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } } diff --git a/Tests/GRPCHTTP2TransportTests/HTTP2TransportNIOPosixTests.swift b/Tests/GRPCHTTP2TransportTests/HTTP2TransportNIOPosixTests.swift index 2d94ce482..70ae83707 100644 --- a/Tests/GRPCHTTP2TransportTests/HTTP2TransportNIOPosixTests.swift +++ b/Tests/GRPCHTTP2TransportTests/HTTP2TransportNIOPosixTests.swift @@ -33,7 +33,7 @@ final class HTTP2TransportNIOPosixTests: XCTestCase { try await withThrowingDiscardingTaskGroup { group in group.addTask { - try await transport.listen { _ in } + try await transport.listen { _, _ in } } group.addTask { @@ -53,7 +53,7 @@ final class HTTP2TransportNIOPosixTests: XCTestCase { try await withThrowingDiscardingTaskGroup { group in group.addTask { - try await transport.listen { _ in } + try await transport.listen { _, _ in } } group.addTask { @@ -73,7 +73,7 @@ final class HTTP2TransportNIOPosixTests: XCTestCase { try await withThrowingDiscardingTaskGroup { group in group.addTask { - try await transport.listen { _ in } + try await transport.listen { _, _ in } } group.addTask { @@ -97,7 +97,7 @@ final class HTTP2TransportNIOPosixTests: XCTestCase { try await withThrowingDiscardingTaskGroup { group in group.addTask { - try await transport.listen { _ in } + try await transport.listen { _, _ in } } group.addTask { @@ -116,7 +116,7 @@ final class HTTP2TransportNIOPosixTests: XCTestCase { try? await withThrowingDiscardingTaskGroup { group in group.addTask { - try await transport.listen { _ in } + try await transport.listen { _, _ in } } group.addTask { @@ -145,7 +145,7 @@ final class HTTP2TransportNIOPosixTests: XCTestCase { try? await withThrowingDiscardingTaskGroup { group in group.addTask { - try await transport.listen { _ in } + try await transport.listen { _, _ in } do { _ = try await transport.listeningAddress diff --git a/Tests/GRPCHTTP2TransportTests/HTTP2TransportNIOTransportServicesTests.swift b/Tests/GRPCHTTP2TransportTests/HTTP2TransportNIOTransportServicesTests.swift index a74d8374e..2afe9e9fa 100644 --- a/Tests/GRPCHTTP2TransportTests/HTTP2TransportNIOTransportServicesTests.swift +++ b/Tests/GRPCHTTP2TransportTests/HTTP2TransportNIOTransportServicesTests.swift @@ -79,7 +79,7 @@ final class HTTP2TransportNIOTransportServicesTests: XCTestCase { try await withThrowingDiscardingTaskGroup { group in group.addTask { - try await transport.listen { _ in } + try await transport.listen { _, _ in } } group.addTask { @@ -99,7 +99,7 @@ final class HTTP2TransportNIOTransportServicesTests: XCTestCase { try await withThrowingDiscardingTaskGroup { group in group.addTask { - try await transport.listen { _ in } + try await transport.listen { _, _ in } } group.addTask { @@ -123,7 +123,7 @@ final class HTTP2TransportNIOTransportServicesTests: XCTestCase { try await withThrowingDiscardingTaskGroup { group in group.addTask { - try await transport.listen { _ in } + try await transport.listen { _, _ in } } group.addTask { @@ -145,7 +145,7 @@ final class HTTP2TransportNIOTransportServicesTests: XCTestCase { try? await withThrowingDiscardingTaskGroup { group in group.addTask { - try await transport.listen { _ in } + try await transport.listen { _, _ in } } group.addTask { @@ -174,7 +174,7 @@ final class HTTP2TransportNIOTransportServicesTests: XCTestCase { try? await withThrowingDiscardingTaskGroup { group in group.addTask { - try await transport.listen { _ in } + try await transport.listen { _, _ in } do { _ = try await transport.listeningAddress diff --git a/Tests/GRPCInProcessTransportTests/InProcessClientTransportTests.swift b/Tests/GRPCInProcessTransportTests/InProcessClientTransportTests.swift index d579ca532..bde6f7bb6 100644 --- a/Tests/GRPCInProcessTransportTests/InProcessClientTransportTests.swift +++ b/Tests/GRPCInProcessTransportTests/InProcessClientTransportTests.swift @@ -171,7 +171,7 @@ final class InProcessClientTransportTests: XCTestCase { } group.addTask { - try await server.listen { stream in + try await server.listen { stream, context in let receivedMessages = try? await stream.inbound.reduce(into: []) { $0.append($1) } try? await stream.outbound.write(RPCResponsePart.message([42])) await stream.outbound.finish() diff --git a/Tests/GRPCInProcessTransportTests/InProcessServerTransportTests.swift b/Tests/GRPCInProcessTransportTests/InProcessServerTransportTests.swift index 7816bc79a..7cd8fed20 100644 --- a/Tests/GRPCInProcessTransportTests/InProcessServerTransportTests.swift +++ b/Tests/GRPCInProcessTransportTests/InProcessServerTransportTests.swift @@ -41,7 +41,8 @@ final class InProcessServerTransportTests: XCTestCase { try await withThrowingTaskGroup(of: Void.self) { group in group.addTask { - try await transport.listen { stream in + try await transport.listen { stream, context in + XCTAssertEqual(context.descriptor, stream.descriptor) let partValue = try? await stream.inbound.reduce(into: []) { $0.append($1) } XCTAssertEqual(partValue, [.message([42])]) transport.beginGracefulShutdown() @@ -71,7 +72,7 @@ final class InProcessServerTransportTests: XCTestCase { try transport.acceptStream(firstStream) - try await transport.listen { stream in + try await transport.listen { stream, context in let firstStreamMessages = try? await stream.inbound.reduce(into: []) { $0.append($1) } diff --git a/Tests/GRPCProtobufCodeGenTests/ProtobufCodeGeneratorTests.swift b/Tests/GRPCProtobufCodeGenTests/ProtobufCodeGeneratorTests.swift index a18fb275c..e192b1e5a 100644 --- a/Tests/GRPCProtobufCodeGenTests/ProtobufCodeGeneratorTests.swift +++ b/Tests/GRPCProtobufCodeGenTests/ProtobufCodeGeneratorTests.swift @@ -241,7 +241,10 @@ final class ProtobufCodeGeneratorTests: XCTestCase { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) public protocol Helloworld_GreeterStreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// Sends a greeting. - func sayHello(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func sayHello( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Conformance to `GRPCCore.RegistrableRPCService`. @@ -253,8 +256,11 @@ final class ProtobufCodeGeneratorTests: XCTestCase { forMethod: Helloworld_Greeter.Method.SayHello.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.sayHello(request: request) + handler: { request, context in + try await self.sayHello( + request: request, + context: context + ) } ) } @@ -264,19 +270,29 @@ final class ProtobufCodeGeneratorTests: XCTestCase { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) public protocol Helloworld_GreeterServiceProtocol: Helloworld_Greeter.StreamingServiceProtocol { /// Sends a greeting. - func sayHello(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func sayHello( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single } /// Partial conformance to `Helloworld_GreeterStreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension Helloworld_Greeter.ServiceProtocol { - public func sayHello(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.sayHello(request: GRPCCore.ServerRequest.Single(stream: request)) + public func sayHello( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.sayHello( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } } """ ) + try testCodeGeneration( proto: Google_Protobuf_FileDescriptorProto.helloWorldEmptyPackage, indentation: 2, @@ -348,7 +364,10 @@ final class ProtobufCodeGeneratorTests: XCTestCase { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) package protocol GreeterStreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// Sends a greeting. - func sayHello(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream + func sayHello( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream } /// Conformance to `GRPCCore.RegistrableRPCService`. @@ -360,8 +379,11 @@ final class ProtobufCodeGeneratorTests: XCTestCase { forMethod: Greeter.Method.SayHello.descriptor, deserializer: GRPCProtobuf.ProtobufDeserializer(), serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request in - try await self.sayHello(request: request) + handler: { request, context in + try await self.sayHello( + request: request, + context: context + ) } ) } @@ -371,14 +393,23 @@ final class ProtobufCodeGeneratorTests: XCTestCase { @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) package protocol GreeterServiceProtocol: Greeter.StreamingServiceProtocol { /// Sends a greeting. - func sayHello(request: GRPCCore.ServerRequest.Single) async throws -> GRPCCore.ServerResponse.Single + func sayHello( + request: GRPCCore.ServerRequest.Single, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Single } /// Partial conformance to `GreeterStreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension Greeter.ServiceProtocol { - package func sayHello(request: GRPCCore.ServerRequest.Stream) async throws -> GRPCCore.ServerResponse.Stream { - let response = try await self.sayHello(request: GRPCCore.ServerRequest.Single(stream: request)) + package func sayHello( + request: GRPCCore.ServerRequest.Stream, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse.Stream { + let response = try await self.sayHello( + request: GRPCCore.ServerRequest.Single(stream: request), + context: context + ) return GRPCCore.ServerResponse.Stream(single: response) } }