| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795 |
- /*
- * 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.
- */
- extension FunctionSignatureDescription {
- /// ```
- /// func <Method>(
- /// request: GRPCCore.ServerRequest<Input>,
- /// context: GRPCCore.ServerContext
- /// ) async throws -> GRPCCore.ServerResponse<Output>
- /// ```
- static func serverMethod(
- accessLevel: AccessModifier? = nil,
- name: String,
- input: String,
- output: String,
- streamingInput: Bool,
- streamingOutput: Bool,
- namer: Namer = Namer()
- ) -> Self {
- return FunctionSignatureDescription(
- accessModifier: accessLevel,
- kind: .function(name: name),
- parameters: [
- ParameterDescription(
- label: "request",
- type: namer.serverRequest(forType: input, isStreaming: streamingInput)
- ),
- ParameterDescription(label: "context", type: namer.serverContext),
- ],
- keywords: [.async, .throws],
- returnType: .identifierType(
- namer.serverResponse(forType: output, isStreaming: streamingOutput)
- )
- )
- }
- }
- extension ProtocolDescription {
- /// ```
- /// protocol <Name>: GRPCCore.RegistrableRPCService {
- /// ...
- /// }
- /// ```
- static func streamingService(
- accessLevel: AccessModifier? = nil,
- name: String,
- methods: [MethodDescriptor],
- namer: Namer = Namer()
- ) -> Self {
- func docs(for method: MethodDescriptor) -> String {
- let summary = """
- /// Handle the "\(method.name.identifyingName)" method.
- """
- let parameters = """
- /// - Parameters:
- /// - request: A streaming request of `\(method.inputType)` messages.
- /// - context: Context providing information about the RPC.
- /// - Throws: Any error which occurred during the processing of the request. Thrown errors
- /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted
- /// to an internal error.
- /// - Returns: A streaming response of `\(method.outputType)` messages.
- """
- return Docs.interposeDocs(method.documentation, between: summary, and: parameters)
- }
- return ProtocolDescription(
- accessModifier: accessLevel,
- name: name,
- conformances: [namer.literalNamespacedType("RegistrableRPCService")],
- members: methods.map { method in
- .commentable(
- .preFormatted(docs(for: method)),
- .function(
- signature: .serverMethod(
- name: method.name.functionName,
- input: method.inputType,
- output: method.outputType,
- streamingInput: true,
- streamingOutput: true,
- namer: namer
- )
- )
- )
- }
- )
- }
- }
- extension ExtensionDescription {
- /// ```
- /// extension <ExtensionName> {
- /// func registerMethods(with router: inout GRPCCore.RPCRouter) {
- /// // ...
- /// }
- /// }
- /// ```
- static func registrableRPCServiceDefaultImplementation(
- accessLevel: AccessModifier? = nil,
- on extensionName: String,
- serviceNamespace: String,
- methods: [MethodDescriptor],
- namer: Namer = Namer(),
- serializer: (String) -> String,
- deserializer: (String) -> String
- ) -> Self {
- return ExtensionDescription(
- onType: extensionName,
- declarations: [
- .function(
- .registerMethods(
- accessLevel: accessLevel,
- serviceNamespace: serviceNamespace,
- methods: methods,
- namer: namer,
- serializer: serializer,
- deserializer: deserializer
- )
- )
- ]
- )
- }
- }
- extension ProtocolDescription {
- /// ```
- /// protocol <Name>: <StreamingProtocol> {
- /// ...
- /// }
- /// ```
- static func service(
- accessLevel: AccessModifier? = nil,
- name: String,
- streamingProtocol: String,
- methods: [MethodDescriptor],
- namer: Namer = Namer()
- ) -> Self {
- func docs(for method: MethodDescriptor) -> String {
- let summary = """
- /// Handle the "\(method.name.identifyingName)" method.
- """
- let request: String
- if method.isInputStreaming {
- request = "A streaming request of `\(method.inputType)` messages."
- } else {
- request = "A request containing a single `\(method.inputType)` message."
- }
- let returns: String
- if method.isOutputStreaming {
- returns = "A streaming response of `\(method.outputType)` messages."
- } else {
- returns = "A response containing a single `\(method.outputType)` message."
- }
- let parameters = """
- /// - Parameters:
- /// - request: \(request)
- /// - context: Context providing information about the RPC.
- /// - Throws: Any error which occurred during the processing of the request. Thrown errors
- /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted
- /// to an internal error.
- /// - Returns: \(returns)
- """
- return Docs.interposeDocs(method.documentation, between: summary, and: parameters)
- }
- return ProtocolDescription(
- accessModifier: accessLevel,
- name: name,
- conformances: [streamingProtocol],
- members: methods.map { method in
- .commentable(
- .preFormatted(docs(for: method)),
- .function(
- signature: .serverMethod(
- name: method.name.functionName,
- input: method.inputType,
- output: method.outputType,
- streamingInput: method.isInputStreaming,
- streamingOutput: method.isOutputStreaming,
- namer: namer
- )
- )
- )
- }
- )
- }
- }
- extension FunctionCallDescription {
- /// ```
- /// self.<Name>(request: request, context: context)
- /// ```
- static func serverMethodCallOnSelf(
- name: String,
- requestArgument: Expression = .identifierPattern("request")
- ) -> Self {
- return FunctionCallDescription(
- calledExpression: .memberAccess(
- MemberAccessDescription(
- left: .identifierPattern("self"),
- right: name
- )
- ),
- arguments: [
- FunctionArgumentDescription(
- label: "request",
- expression: requestArgument
- ),
- FunctionArgumentDescription(
- label: "context",
- expression: .identifierPattern("context")
- ),
- ]
- )
- }
- }
- extension ClosureInvocationDescription {
- /// ```
- /// { router, context in
- /// try await self.<Method>(
- /// request: request,
- /// context: context
- /// )
- /// }
- /// ```
- static func routerHandlerInvokingRPC(method: String) -> Self {
- return ClosureInvocationDescription(
- argumentNames: ["request", "context"],
- body: [
- .expression(
- .unaryKeyword(
- kind: .try,
- expression: .unaryKeyword(
- kind: .await,
- expression: .functionCall(.serverMethodCallOnSelf(name: method))
- )
- )
- )
- ]
- )
- }
- }
- /// ```
- /// router.registerHandler(
- /// forMethod: ...,
- /// deserializer: ...
- /// serializer: ...
- /// handler: { request, context in
- /// // ...
- /// }
- /// )
- /// ```
- extension FunctionCallDescription {
- static func registerWithRouter(
- serviceNamespace: String,
- methodNamespace: String,
- methodName: String,
- inputDeserializer: String,
- outputSerializer: String
- ) -> Self {
- return FunctionCallDescription(
- calledExpression: .memberAccess(
- .init(left: .identifierPattern("router"), right: "registerHandler")
- ),
- arguments: [
- FunctionArgumentDescription(
- label: "forMethod",
- expression: .identifierPattern("\(serviceNamespace).Method.\(methodNamespace).descriptor")
- ),
- FunctionArgumentDescription(
- label: "deserializer",
- expression: .identifierPattern(inputDeserializer)
- ),
- FunctionArgumentDescription(
- label: "serializer",
- expression: .identifierPattern(outputSerializer)
- ),
- FunctionArgumentDescription(
- label: "handler",
- expression: .closureInvocation(.routerHandlerInvokingRPC(method: methodName))
- ),
- ]
- )
- }
- }
- extension FunctionDescription {
- /// ```
- /// func registerMethods(with router: inout GRPCCore.RPCRouter) {
- /// // ...
- /// }
- /// ```
- static func registerMethods(
- accessLevel: AccessModifier? = nil,
- serviceNamespace: String,
- methods: [MethodDescriptor],
- namer: Namer = Namer(),
- serializer: (String) -> String,
- deserializer: (String) -> String
- ) -> Self {
- return FunctionDescription(
- accessModifier: accessLevel,
- kind: .function(name: "registerMethods"),
- generics: [.member("Transport")],
- parameters: [
- ParameterDescription(
- label: "with",
- name: "router",
- type: namer.rpcRouter(genericOver: "Transport"),
- `inout`: true
- )
- ],
- whereClause: WhereClause(
- requirements: [
- .conformance("Transport", namer.literalNamespacedType("ServerTransport"))
- ]
- ),
- body: methods.map { method in
- .functionCall(
- .registerWithRouter(
- serviceNamespace: serviceNamespace,
- methodNamespace: method.name.typeName,
- methodName: method.name.functionName,
- inputDeserializer: deserializer(method.inputType),
- outputSerializer: serializer(method.outputType)
- )
- )
- }
- )
- }
- }
- extension FunctionDescription {
- /// ```
- /// func <Name>(
- /// request: GRPCCore.StreamingServerRequest<Input>
- /// context: GRPCCore.ServerContext
- /// ) async throws -> GRPCCore.StreamingServerResponse<Output> {
- /// let response = try await self.<Name>(
- /// request: GRPCCore.ServerRequest(stream: request),
- /// context: context
- /// )
- /// return GRPCCore.StreamingServerResponse(single: response)
- /// }
- /// ```
- static func serverStreamingMethodsCallingMethod(
- accessLevel: AccessModifier? = nil,
- name: String,
- input: String,
- output: String,
- streamingInput: Bool,
- streamingOutput: Bool,
- namer: Namer = Namer()
- ) -> FunctionDescription {
- let signature: FunctionSignatureDescription = .serverMethod(
- accessLevel: accessLevel,
- name: name,
- input: input,
- output: output,
- // This method converts from the fully streamed version to the specified version.
- streamingInput: true,
- streamingOutput: true,
- namer: namer
- )
- // Call the underlying function.
- let functionCall: Expression = .functionCall(
- calledExpression: .memberAccess(
- MemberAccessDescription(
- left: .identifierPattern("self"),
- right: name
- )
- ),
- arguments: [
- FunctionArgumentDescription(
- label: "request",
- expression: streamingInput
- ? .identifierPattern("request")
- : .functionCall(
- calledExpression: .identifierType(
- namer.serverRequest(forType: nil, isStreaming: false)
- ),
- arguments: [
- FunctionArgumentDescription(
- label: "stream",
- expression: .identifierPattern("request")
- )
- ]
- )
- ),
- FunctionArgumentDescription(
- label: "context",
- expression: .identifierPattern("context")
- ),
- ]
- )
- // Call the function and assign to 'response'.
- let response: Declaration = .variable(
- kind: .let,
- left: "response",
- right: .unaryKeyword(
- kind: .try,
- expression: .unaryKeyword(
- kind: .await,
- expression: functionCall
- )
- )
- )
- // Build the return statement.
- let returnExpression: Expression = .unaryKeyword(
- kind: .return,
- expression: streamingOutput
- ? .identifierPattern("response")
- : .functionCall(
- calledExpression: .identifierType(namer.serverResponse(forType: nil, isStreaming: true)),
- arguments: [
- FunctionArgumentDescription(
- label: "single",
- expression: .identifierPattern("response")
- )
- ]
- )
- )
- return Self(
- signature: signature,
- body: [.declaration(response), .expression(returnExpression)]
- )
- }
- }
- extension ExtensionDescription {
- /// ```
- /// extension <ExtensionName> {
- /// func <Name>(
- /// request: GRPCCore.StreamingServerRequest<Input>
- /// context: GRPCCore.ServerContext
- /// ) async throws -> GRPCCore.StreamingServerResponse<Output> {
- /// let response = try await self.<Name>(
- /// request: GRPCCore.ServerRequest(stream: request),
- /// context: context
- /// )
- /// return GRPCCore.StreamingServerResponse(single: response)
- /// }
- /// ...
- /// }
- /// ```
- static func streamingServiceProtocolDefaultImplementation(
- accessModifier: AccessModifier? = nil,
- on extensionName: String,
- methods: [MethodDescriptor],
- namer: Namer = Namer()
- ) -> Self {
- return ExtensionDescription(
- onType: extensionName,
- declarations: methods.compactMap { method -> Declaration? in
- // Bidirectional streaming methods don't need a default implementation as their signatures
- // match across the two protocols.
- if method.isInputStreaming, method.isOutputStreaming { return nil }
- return .function(
- .serverStreamingMethodsCallingMethod(
- accessLevel: accessModifier,
- name: method.name.functionName,
- input: method.inputType,
- output: method.outputType,
- streamingInput: method.isInputStreaming,
- streamingOutput: method.isOutputStreaming,
- namer: namer
- )
- )
- }
- )
- }
- }
- extension FunctionSignatureDescription {
- /// ```
- /// func <Name>(
- /// request: <Input>,
- /// context: GRPCCore.ServerContext,
- /// ) async throws -> <Output>
- /// ```
- ///
- /// ```
- /// func <Name>(
- /// request: GRPCCore.RPCAsyncSequence<Input, any Error>,
- /// response: GRPCCore.RPCAsyncWriter<Output>
- /// context: GRPCCore.ServerContext,
- /// ) async throws
- /// ```
- static func simpleServerMethod(
- accessLevel: AccessModifier? = nil,
- name: String,
- input: String,
- output: String,
- streamingInput: Bool,
- streamingOutput: Bool,
- namer: Namer = Namer()
- ) -> Self {
- var parameters: [ParameterDescription] = [
- ParameterDescription(
- label: "request",
- type: streamingInput ? namer.rpcAsyncSequence(forType: input) : .member(input)
- )
- ]
- if streamingOutput {
- parameters.append(
- ParameterDescription(
- label: "response",
- type: namer.rpcWriter(forType: output)
- )
- )
- }
- parameters.append(ParameterDescription(label: "context", type: namer.serverContext))
- return FunctionSignatureDescription(
- accessModifier: accessLevel,
- kind: .function(name: name),
- parameters: parameters,
- keywords: [.async, .throws],
- returnType: streamingOutput ? nil : .identifier(.pattern(output))
- )
- }
- }
- extension ProtocolDescription {
- /// ```
- /// protocol SimpleServiceProtocol: <ServiceProtocol> {
- /// ...
- /// }
- /// ```
- static func simpleServiceProtocol(
- accessModifier: AccessModifier? = nil,
- name: String,
- serviceProtocol: String,
- methods: [MethodDescriptor],
- namer: Namer = Namer()
- ) -> Self {
- func docs(for method: MethodDescriptor) -> String {
- let summary = """
- /// Handle the "\(method.name.identifyingName)" method.
- """
- let requestText =
- method.isInputStreaming
- ? "A stream of `\(method.inputType)` messages."
- : "A `\(method.inputType)` message."
- var parameters = """
- /// - Parameters:
- /// - request: \(requestText)
- """
- if method.isOutputStreaming {
- parameters += "\n"
- parameters += """
- /// - response: A response stream of `\(method.outputType)` messages.
- """
- }
- parameters += "\n"
- parameters += """
- /// - context: Context providing information about the RPC.
- /// - Throws: Any error which occurred during the processing of the request. Thrown errors
- /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted
- /// to an internal error.
- """
- if !method.isOutputStreaming {
- parameters += "\n"
- parameters += """
- /// - Returns: A `\(method.outputType)` to respond with.
- """
- }
- return Docs.interposeDocs(method.documentation, between: summary, and: parameters)
- }
- return ProtocolDescription(
- accessModifier: accessModifier,
- name: name,
- conformances: [serviceProtocol],
- members: methods.map { method in
- .commentable(
- .preFormatted(docs(for: method)),
- .function(
- signature: .simpleServerMethod(
- name: method.name.functionName,
- input: method.inputType,
- output: method.outputType,
- streamingInput: method.isInputStreaming,
- streamingOutput: method.isOutputStreaming,
- namer: namer
- )
- )
- )
- }
- )
- }
- }
- extension FunctionCallDescription {
- /// ```
- /// try await self.<Name>(
- /// request: request.message,
- /// response: writer,
- /// context: context
- /// )
- /// ```
- static func serviceMethodCallingSimpleMethod(
- name: String,
- input: String,
- output: String,
- streamingInput: Bool,
- streamingOutput: Bool
- ) -> Self {
- var arguments: [FunctionArgumentDescription] = [
- FunctionArgumentDescription(
- label: "request",
- expression: .identifierPattern("request").dot(streamingInput ? "messages" : "message")
- )
- ]
- if streamingOutput {
- arguments.append(
- FunctionArgumentDescription(
- label: "response",
- expression: .identifierPattern("writer")
- )
- )
- }
- arguments.append(
- FunctionArgumentDescription(
- label: "context",
- expression: .identifierPattern("context")
- )
- )
- return FunctionCallDescription(
- calledExpression: .try(.await(.identifierPattern("self").dot(name))),
- arguments: arguments
- )
- }
- }
- extension FunctionDescription {
- /// ```
- /// func <Name>(
- /// request: GRPCCore.ServerRequest<Input>,
- /// context: GRPCCore.ServerContext
- /// ) async throws -> GRPCCore.ServerResponse<Output> {
- /// return GRPCCore.ServerResponse<Output>(
- /// message: try await self.<Name>(
- /// request: request.message,
- /// context: context
- /// )
- /// metadata: [:]
- /// )
- /// }
- /// ```
- static func serviceProtocolDefaultImplementation(
- accessModifier: AccessModifier? = nil,
- name: String,
- input: String,
- output: String,
- streamingInput: Bool,
- streamingOutput: Bool,
- namer: Namer = Namer()
- ) -> Self {
- func makeUnaryOutputArguments() -> [FunctionArgumentDescription] {
- return [
- FunctionArgumentDescription(
- label: "message",
- expression: .functionCall(
- .serviceMethodCallingSimpleMethod(
- name: name,
- input: input,
- output: output,
- streamingInput: streamingInput,
- streamingOutput: streamingOutput
- )
- )
- ),
- FunctionArgumentDescription(label: "metadata", expression: .literal(.dictionary([]))),
- ]
- }
- func makeStreamingOutputArguments() -> [FunctionArgumentDescription] {
- return [
- FunctionArgumentDescription(label: "metadata", expression: .literal(.dictionary([]))),
- FunctionArgumentDescription(
- label: "producer",
- expression: .closureInvocation(
- argumentNames: ["writer"],
- body: [
- .expression(
- .functionCall(
- .serviceMethodCallingSimpleMethod(
- name: name,
- input: input,
- output: output,
- streamingInput: streamingInput,
- streamingOutput: streamingOutput
- )
- )
- ),
- .expression(.return(.literal(.dictionary([])))),
- ]
- )
- ),
- ]
- }
- return FunctionDescription(
- signature: .serverMethod(
- accessLevel: accessModifier,
- name: name,
- input: input,
- output: output,
- streamingInput: streamingInput,
- streamingOutput: streamingOutput,
- namer: namer
- ),
- body: [
- .expression(
- .functionCall(
- calledExpression: .return(
- .identifierType(
- namer.serverResponse(forType: output, isStreaming: streamingOutput)
- )
- ),
- arguments: streamingOutput ? makeStreamingOutputArguments() : makeUnaryOutputArguments()
- )
- )
- ]
- )
- }
- }
- extension ExtensionDescription {
- /// ```
- /// extension ServiceProtocol {
- /// ...
- /// }
- /// ```
- static func serviceProtocolDefaultImplementation(
- accessModifier: AccessModifier? = nil,
- on extensionName: String,
- methods: [MethodDescriptor],
- namer: Namer = Namer()
- ) -> Self {
- ExtensionDescription(
- onType: extensionName,
- declarations: methods.map { method in
- .function(
- .serviceProtocolDefaultImplementation(
- accessModifier: accessModifier,
- name: method.name.functionName,
- input: method.inputType,
- output: method.outputType,
- streamingInput: method.isInputStreaming,
- streamingOutput: method.isOutputStreaming,
- namer: namer
- )
- )
- }
- )
- }
- }
|