RPCRouter.swift 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /*
  2. * Copyright 2023, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /// Stores and provides handlers for RPCs.
  17. ///
  18. /// The router stores a handler for each RPC it knows about. Each handler encapsulate the business
  19. /// logic for the RPC which is typically implemented by service owners. To register a handler you
  20. /// can call ``registerHandler(forMethod:deserializer:serializer:handler:)``. You can check whether
  21. /// the router has a handler for a method with ``hasHandler(forMethod:)`` or get a list of all
  22. /// methods with handlers registered by calling ``methods``. You can also remove the handler for a
  23. /// given method by calling ``removeHandler(forMethod:)``.
  24. ///
  25. /// In most cases you won't need to interact with the router directly. Instead you should register
  26. /// your services with ``GRPCServer/init(transport:services:interceptors:)`` which will in turn
  27. /// register each method with the router.
  28. ///
  29. /// You may wish to not serve all methods from your service in which case you can either:
  30. ///
  31. /// 1. Remove individual methods by calling ``removeHandler(forMethod:)``, or
  32. /// 2. Implement ``RegistrableRPCService/registerMethods(with:)`` to register only the methods you
  33. /// want to be served.
  34. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  35. public struct RPCRouter: Sendable {
  36. @usableFromInline
  37. struct RPCHandler: Sendable {
  38. @usableFromInline
  39. let _fn:
  40. @Sendable (
  41. _ stream: RPCStream<
  42. RPCAsyncSequence<RPCRequestPart, any Error>,
  43. RPCWriter<RPCResponsePart>.Closable
  44. >,
  45. _ context: ServerContext,
  46. _ interceptors: [any ServerInterceptor]
  47. ) async -> Void
  48. @inlinable
  49. init<Input, Output>(
  50. method: MethodDescriptor,
  51. deserializer: some MessageDeserializer<Input>,
  52. serializer: some MessageSerializer<Output>,
  53. handler: @Sendable @escaping (
  54. _ request: ServerRequest.Stream<Input>,
  55. _ context: ServerContext
  56. ) async throws -> ServerResponse.Stream<Output>
  57. ) {
  58. self._fn = { stream, context, interceptors in
  59. await ServerRPCExecutor.execute(
  60. context: context,
  61. stream: stream,
  62. deserializer: deserializer,
  63. serializer: serializer,
  64. interceptors: interceptors,
  65. handler: handler
  66. )
  67. }
  68. }
  69. @inlinable
  70. func handle(
  71. stream: RPCStream<
  72. RPCAsyncSequence<RPCRequestPart, any Error>,
  73. RPCWriter<RPCResponsePart>.Closable
  74. >,
  75. context: ServerContext,
  76. interceptors: [any ServerInterceptor]
  77. ) async {
  78. await self._fn(stream, context, interceptors)
  79. }
  80. }
  81. @usableFromInline
  82. private(set) var handlers: [MethodDescriptor: RPCHandler]
  83. /// Creates a new router with no methods registered.
  84. public init() {
  85. self.handlers = [:]
  86. }
  87. /// Returns all descriptors known to the router in an undefined order.
  88. public var methods: [MethodDescriptor] {
  89. Array(self.handlers.keys)
  90. }
  91. /// Returns the number of methods registered with the router.
  92. public var count: Int {
  93. self.handlers.count
  94. }
  95. /// Returns whether a handler exists for a given method.
  96. ///
  97. /// - Parameter descriptor: A descriptor of the method.
  98. /// - Returns: Whether a handler exists for the method.
  99. public func hasHandler(forMethod descriptor: MethodDescriptor) -> Bool {
  100. return self.handlers.keys.contains(descriptor)
  101. }
  102. /// Registers a handler with the router.
  103. ///
  104. /// - Note: if a handler already exists for a given method then it will be replaced.
  105. ///
  106. /// - Parameters:
  107. /// - descriptor: A descriptor for the method to register a handler for.
  108. /// - deserializer: A deserializer to deserialize input messages received from the client.
  109. /// - serializer: A serializer to serialize output messages to send to the client.
  110. /// - handler: The function which handles the request and returns a response.
  111. @inlinable
  112. public mutating func registerHandler<Input: Sendable, Output: Sendable>(
  113. forMethod descriptor: MethodDescriptor,
  114. deserializer: some MessageDeserializer<Input>,
  115. serializer: some MessageSerializer<Output>,
  116. handler: @Sendable @escaping (
  117. _ request: ServerRequest.Stream<Input>,
  118. _ context: ServerContext
  119. ) async throws -> ServerResponse.Stream<Output>
  120. ) {
  121. self.handlers[descriptor] = RPCHandler(
  122. method: descriptor,
  123. deserializer: deserializer,
  124. serializer: serializer,
  125. handler: handler
  126. )
  127. }
  128. /// Removes any handler registered for the specified method.
  129. ///
  130. /// - Parameter descriptor: A descriptor of the method to remove a handler for.
  131. /// - Returns: Whether a handler was removed.
  132. @discardableResult
  133. public mutating func removeHandler(forMethod descriptor: MethodDescriptor) -> Bool {
  134. return self.handlers.removeValue(forKey: descriptor) != nil
  135. }
  136. }
  137. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  138. extension RPCRouter {
  139. internal func handle(
  140. stream: RPCStream<
  141. RPCAsyncSequence<RPCRequestPart, any Error>,
  142. RPCWriter<RPCResponsePart>.Closable
  143. >,
  144. context: ServerContext,
  145. interceptors: [any ServerInterceptor]
  146. ) async {
  147. if let handler = self.handlers[stream.descriptor] {
  148. await handler.handle(stream: stream, context: context, interceptors: interceptors)
  149. } else {
  150. // If this throws then the stream must be closed which we can't do anything about, so ignore
  151. // any error.
  152. try? await stream.outbound.write(.status(.rpcNotImplemented, [:]))
  153. await stream.outbound.finish()
  154. }
  155. }
  156. }
  157. extension Status {
  158. fileprivate static let rpcNotImplemented = Status(
  159. code: .unimplemented,
  160. message: "Requested RPC isn't implemented by this server."
  161. )
  162. }